First Commit
This commit is contained in:
166
3rdparty/plutosvg/plutovg/source/FTL.TXT
vendored
Normal file
166
3rdparty/plutosvg/plutovg/source/FTL.TXT
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
The FreeType Project LICENSE
|
||||
----------------------------
|
||||
|
||||
2006-Jan-27
|
||||
|
||||
Copyright 1996-2002, 2006 by
|
||||
David Turner, Robert Wilhelm, and Werner Lemberg
|
||||
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The FreeType Project is distributed in several archive packages;
|
||||
some of them may contain, in addition to the FreeType font engine,
|
||||
various tools and contributions which rely on, or relate to, the
|
||||
FreeType Project.
|
||||
|
||||
This license applies to all files found in such packages, and
|
||||
which do not fall under their own explicit license. The license
|
||||
affects thus the FreeType font engine, the test programs,
|
||||
documentation and makefiles, at the very least.
|
||||
|
||||
This license was inspired by the BSD, Artistic, and IJG
|
||||
(Independent JPEG Group) licenses, which all encourage inclusion
|
||||
and use of free software in commercial and freeware products
|
||||
alike. As a consequence, its main points are that:
|
||||
|
||||
o We don't promise that this software works. However, we will be
|
||||
interested in any kind of bug reports. (`as is' distribution)
|
||||
|
||||
o You can use this software for whatever you want, in parts or
|
||||
full form, without having to pay us. (`royalty-free' usage)
|
||||
|
||||
o You may not pretend that you wrote this software. If you use
|
||||
it, or only parts of it, in a program, you must acknowledge
|
||||
somewhere in your documentation that you have used the
|
||||
FreeType code. (`credits')
|
||||
|
||||
We specifically permit and encourage the inclusion of this
|
||||
software, with or without modifications, in commercial products.
|
||||
We disclaim all warranties covering The FreeType Project and
|
||||
assume no liability related to The FreeType Project.
|
||||
|
||||
|
||||
Finally, many people asked us for a preferred form for a
|
||||
credit/disclaimer to use in compliance with this license. We thus
|
||||
encourage you to use the following text:
|
||||
|
||||
"""
|
||||
Portions of this software are copyright <20> <year> The FreeType
|
||||
Project (www.freetype.org). All rights reserved.
|
||||
"""
|
||||
|
||||
Please replace <year> with the value from the FreeType version you
|
||||
actually use.
|
||||
|
||||
|
||||
Legal Terms
|
||||
===========
|
||||
|
||||
0. Definitions
|
||||
--------------
|
||||
|
||||
Throughout this license, the terms `package', `FreeType Project',
|
||||
and `FreeType archive' refer to the set of files originally
|
||||
distributed by the authors (David Turner, Robert Wilhelm, and
|
||||
Werner Lemberg) as the `FreeType Project', be they named as alpha,
|
||||
beta or final release.
|
||||
|
||||
`You' refers to the licensee, or person using the project, where
|
||||
`using' is a generic term including compiling the project's source
|
||||
code as well as linking it to form a `program' or `executable'.
|
||||
This program is referred to as `a program using the FreeType
|
||||
engine'.
|
||||
|
||||
This license applies to all files distributed in the original
|
||||
FreeType Project, including all source code, binaries and
|
||||
documentation, unless otherwise stated in the file in its
|
||||
original, unmodified form as distributed in the original archive.
|
||||
If you are unsure whether or not a particular file is covered by
|
||||
this license, you must contact us to verify this.
|
||||
|
||||
The FreeType Project is copyright (C) 1996-2000 by David Turner,
|
||||
Robert Wilhelm, and Werner Lemberg. All rights reserved except as
|
||||
specified below.
|
||||
|
||||
1. No Warranty
|
||||
--------------
|
||||
|
||||
THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO
|
||||
USE, OF THE FREETYPE PROJECT.
|
||||
|
||||
2. Redistribution
|
||||
-----------------
|
||||
|
||||
This license grants a worldwide, royalty-free, perpetual and
|
||||
irrevocable right and license to use, execute, perform, compile,
|
||||
display, copy, create derivative works of, distribute and
|
||||
sublicense the FreeType Project (in both source and object code
|
||||
forms) and derivative works thereof for any purpose; and to
|
||||
authorize others to exercise some or all of the rights granted
|
||||
herein, subject to the following conditions:
|
||||
|
||||
o Redistribution of source code must retain this license file
|
||||
(`FTL.TXT') unaltered; any additions, deletions or changes to
|
||||
the original files must be clearly indicated in accompanying
|
||||
documentation. The copyright notices of the unaltered,
|
||||
original files must be preserved in all copies of source
|
||||
files.
|
||||
|
||||
o Redistribution in binary form must provide a disclaimer that
|
||||
states that the software is based in part of the work of the
|
||||
FreeType Team, in the distribution documentation. We also
|
||||
encourage you to put an URL to the FreeType web page in your
|
||||
documentation, though this isn't mandatory.
|
||||
|
||||
These conditions apply to any software derived from or based on
|
||||
the FreeType Project, not just the unmodified files. If you use
|
||||
our work, you must acknowledge us. However, no fee need be paid
|
||||
to us.
|
||||
|
||||
3. Advertising
|
||||
--------------
|
||||
|
||||
Neither the FreeType authors and contributors nor you shall use
|
||||
the name of the other for commercial, advertising, or promotional
|
||||
purposes without specific prior written permission.
|
||||
|
||||
We suggest, but do not require, that you use one or more of the
|
||||
following phrases to refer to this software in your documentation
|
||||
or advertising materials: `FreeType Project', `FreeType Engine',
|
||||
`FreeType library', or `FreeType Distribution'.
|
||||
|
||||
As you have not signed this license, you are not required to
|
||||
accept it. However, as the FreeType Project is copyrighted
|
||||
material, only this license, or another one contracted with the
|
||||
authors, grants you the right to use, distribute, and modify it.
|
||||
Therefore, by using, distributing, or modifying the FreeType
|
||||
Project, you indicate that you understand and accept all the terms
|
||||
of this license.
|
||||
|
||||
4. Contacts
|
||||
-----------
|
||||
|
||||
There are two mailing lists related to FreeType:
|
||||
|
||||
o freetype@nongnu.org
|
||||
|
||||
Discusses general use and applications of FreeType, as well as
|
||||
future and wanted additions to the library and distribution.
|
||||
If you are looking for support, start in this list if you
|
||||
haven't found anything to help you in the documentation.
|
||||
|
||||
o freetype-devel@nongnu.org
|
||||
|
||||
Discusses bugs, as well as engine internals, design issues,
|
||||
specific licenses, porting, etc.
|
||||
|
||||
Our home page can be found at
|
||||
|
||||
http://www.freetype.org
|
||||
1051
3rdparty/plutosvg/plutovg/source/plutovg-blend.c
vendored
Normal file
1051
3rdparty/plutosvg/plutovg/source/plutovg-blend.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
714
3rdparty/plutosvg/plutovg/source/plutovg-canvas.c
vendored
Normal file
714
3rdparty/plutosvg/plutovg/source/plutovg-canvas.c
vendored
Normal file
@@ -0,0 +1,714 @@
|
||||
#include "plutovg-private.h"
|
||||
#include "plutovg-utils.h"
|
||||
|
||||
int plutovg_version(void)
|
||||
{
|
||||
return PLUTOVG_VERSION;
|
||||
}
|
||||
|
||||
const char* plutovg_version_string(void)
|
||||
{
|
||||
return PLUTOVG_VERSION_STRING;
|
||||
}
|
||||
|
||||
#define PLUTOVG_DEFAULT_STROKE_STYLE ((plutovg_stroke_style_t){1.f, PLUTOVG_LINE_CAP_BUTT, PLUTOVG_LINE_JOIN_MITER, 10.f})
|
||||
|
||||
static plutovg_state_t* plutovg_state_create(void)
|
||||
{
|
||||
plutovg_state_t* state = malloc(sizeof(plutovg_state_t));
|
||||
state->paint = NULL;
|
||||
state->font_face = NULL;
|
||||
state->color = PLUTOVG_BLACK_COLOR;
|
||||
state->matrix = PLUTOVG_IDENTITY_MATRIX;
|
||||
state->stroke.style = PLUTOVG_DEFAULT_STROKE_STYLE;
|
||||
state->stroke.dash.offset = 0.f;
|
||||
plutovg_array_init(state->stroke.dash.array);
|
||||
plutovg_span_buffer_init(&state->clip_spans);
|
||||
state->winding = PLUTOVG_FILL_RULE_NON_ZERO;
|
||||
state->op = PLUTOVG_OPERATOR_SRC_OVER;
|
||||
state->font_size = 12.f;
|
||||
state->opacity = 1.f;
|
||||
state->clipping = false;
|
||||
state->next = NULL;
|
||||
return state;
|
||||
}
|
||||
|
||||
static void plutovg_state_reset(plutovg_state_t* state)
|
||||
{
|
||||
plutovg_paint_destroy(state->paint);
|
||||
plutovg_font_face_destroy(state->font_face);
|
||||
state->paint = NULL;
|
||||
state->font_face = NULL;
|
||||
state->color = PLUTOVG_BLACK_COLOR;
|
||||
state->matrix = PLUTOVG_IDENTITY_MATRIX;
|
||||
state->stroke.style = PLUTOVG_DEFAULT_STROKE_STYLE;
|
||||
state->stroke.dash.offset = 0.f;
|
||||
plutovg_array_clear(state->stroke.dash.array);
|
||||
plutovg_span_buffer_reset(&state->clip_spans);
|
||||
state->winding = PLUTOVG_FILL_RULE_NON_ZERO;
|
||||
state->op = PLUTOVG_OPERATOR_SRC_OVER;
|
||||
state->font_size = 12.f;
|
||||
state->opacity = 1.f;
|
||||
state->clipping = false;
|
||||
}
|
||||
|
||||
static void plutovg_state_copy(plutovg_state_t* state, const plutovg_state_t* source)
|
||||
{
|
||||
state->paint = plutovg_paint_reference(source->paint);
|
||||
state->font_face = plutovg_font_face_reference(source->font_face);
|
||||
state->color = source->color;
|
||||
state->matrix = source->matrix;
|
||||
state->stroke.style = source->stroke.style;
|
||||
state->stroke.dash.offset = source->stroke.dash.offset;
|
||||
plutovg_array_clear(state->stroke.dash.array);
|
||||
plutovg_array_append(state->stroke.dash.array, source->stroke.dash.array);
|
||||
plutovg_span_buffer_copy(&state->clip_spans, &source->clip_spans);
|
||||
state->winding = source->winding;
|
||||
state->op = source->op;
|
||||
state->font_size = source->font_size;
|
||||
state->opacity = source->opacity;
|
||||
state->clipping = source->clipping;
|
||||
}
|
||||
|
||||
static void plutovg_state_destroy(plutovg_state_t* state)
|
||||
{
|
||||
plutovg_paint_destroy(state->paint);
|
||||
plutovg_font_face_destroy(state->font_face);
|
||||
plutovg_array_destroy(state->stroke.dash.array);
|
||||
plutovg_span_buffer_destroy(&state->clip_spans);
|
||||
free(state);
|
||||
}
|
||||
|
||||
plutovg_canvas_t* plutovg_canvas_create(plutovg_surface_t* surface)
|
||||
{
|
||||
plutovg_canvas_t* canvas = malloc(sizeof(plutovg_canvas_t));
|
||||
canvas->ref_count = 1;
|
||||
canvas->surface = plutovg_surface_reference(surface);
|
||||
canvas->path = plutovg_path_create();
|
||||
canvas->state = plutovg_state_create();
|
||||
canvas->freed_state = NULL;
|
||||
canvas->clip_rect = PLUTOVG_MAKE_RECT(0, 0, surface->width, surface->height);
|
||||
plutovg_span_buffer_init(&canvas->clip_spans);
|
||||
plutovg_span_buffer_init(&canvas->fill_spans);
|
||||
return canvas;
|
||||
}
|
||||
|
||||
plutovg_canvas_t* plutovg_canvas_reference(plutovg_canvas_t* canvas)
|
||||
{
|
||||
if(canvas == NULL)
|
||||
return NULL;
|
||||
++canvas->ref_count;
|
||||
return canvas;
|
||||
}
|
||||
|
||||
void plutovg_canvas_destroy(plutovg_canvas_t* canvas)
|
||||
{
|
||||
if(canvas == NULL)
|
||||
return;
|
||||
if(--canvas->ref_count == 0) {
|
||||
while(canvas->state) {
|
||||
plutovg_state_t* state = canvas->state;
|
||||
canvas->state = state->next;
|
||||
plutovg_state_destroy(state);
|
||||
}
|
||||
|
||||
while(canvas->freed_state) {
|
||||
plutovg_state_t* state = canvas->freed_state;
|
||||
canvas->freed_state = state->next;
|
||||
plutovg_state_destroy(state);
|
||||
}
|
||||
|
||||
plutovg_span_buffer_destroy(&canvas->fill_spans);
|
||||
plutovg_span_buffer_destroy(&canvas->clip_spans);
|
||||
plutovg_surface_destroy(canvas->surface);
|
||||
plutovg_path_destroy(canvas->path);
|
||||
free(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
int plutovg_canvas_get_reference_count(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
if(canvas == NULL)
|
||||
return 0;
|
||||
return canvas->ref_count;
|
||||
}
|
||||
|
||||
plutovg_surface_t* plutovg_canvas_get_surface(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
return canvas->surface;
|
||||
}
|
||||
|
||||
void plutovg_canvas_save(plutovg_canvas_t* canvas)
|
||||
{
|
||||
plutovg_state_t* new_state = canvas->freed_state;
|
||||
if(new_state == NULL)
|
||||
new_state = plutovg_state_create();
|
||||
else
|
||||
canvas->freed_state = new_state->next;
|
||||
plutovg_state_copy(new_state, canvas->state);
|
||||
new_state->next = canvas->state;
|
||||
canvas->state = new_state;
|
||||
}
|
||||
|
||||
void plutovg_canvas_restore(plutovg_canvas_t* canvas)
|
||||
{
|
||||
if(canvas->state->next == NULL)
|
||||
return;
|
||||
plutovg_state_t* old_state = canvas->state;
|
||||
canvas->state = old_state->next;
|
||||
plutovg_state_reset(old_state);
|
||||
old_state->next = canvas->freed_state;
|
||||
canvas->freed_state = old_state;
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_rgb(plutovg_canvas_t* canvas, float r, float g, float b)
|
||||
{
|
||||
plutovg_canvas_set_rgba(canvas, r, g, b, 1.f);
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_rgba(plutovg_canvas_t* canvas, float r, float g, float b, float a)
|
||||
{
|
||||
plutovg_color_init_rgba(&canvas->state->color, r, g, b, a);
|
||||
plutovg_canvas_set_paint(canvas, NULL);
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_color(plutovg_canvas_t* canvas, const plutovg_color_t* color)
|
||||
{
|
||||
plutovg_canvas_set_rgba(canvas, color->r, color->g, color->b, color->a);
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_linear_gradient(plutovg_canvas_t* canvas, float x1, float y1, float x2, float y2, plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix)
|
||||
{
|
||||
plutovg_paint_t* paint = plutovg_paint_create_linear_gradient(x1, y1, x2, y2, spread, stops, nstops, matrix);
|
||||
plutovg_canvas_set_paint(canvas, paint);
|
||||
plutovg_paint_destroy(paint);
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_radial_gradient(plutovg_canvas_t* canvas, float cx, float cy, float cr, float fx, float fy, float fr, plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix)
|
||||
{
|
||||
plutovg_paint_t* paint = plutovg_paint_create_radial_gradient(cx, cy, cr, fx, fy, fr, spread, stops, nstops, matrix);
|
||||
plutovg_canvas_set_paint(canvas, paint);
|
||||
plutovg_paint_destroy(paint);
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_texture(plutovg_canvas_t* canvas, plutovg_surface_t* surface, plutovg_texture_type_t type, float opacity, const plutovg_matrix_t* matrix)
|
||||
{
|
||||
plutovg_paint_t* paint = plutovg_paint_create_texture(surface, type, opacity, matrix);
|
||||
plutovg_canvas_set_paint(canvas, paint);
|
||||
plutovg_paint_destroy(paint);
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_paint(plutovg_canvas_t* canvas, plutovg_paint_t* paint)
|
||||
{
|
||||
paint = plutovg_paint_reference(paint);
|
||||
plutovg_paint_destroy(canvas->state->paint);
|
||||
canvas->state->paint = paint;
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_canvas_get_paint(const plutovg_canvas_t* canvas, plutovg_color_t* color)
|
||||
{
|
||||
if(color)
|
||||
*color = canvas->state->color;
|
||||
return canvas->state->paint;
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_font(plutovg_canvas_t* canvas, plutovg_font_face_t* face, float size)
|
||||
{
|
||||
plutovg_canvas_set_font_face(canvas, face);
|
||||
plutovg_canvas_set_font_size(canvas, size);
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_font_face(plutovg_canvas_t* canvas, plutovg_font_face_t* face)
|
||||
{
|
||||
face = plutovg_font_face_reference(face);
|
||||
plutovg_font_face_destroy(canvas->state->font_face);
|
||||
canvas->state->font_face = face;
|
||||
}
|
||||
|
||||
plutovg_font_face_t* plutovg_canvas_get_font_face(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
return canvas->state->font_face;
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_font_size(plutovg_canvas_t* canvas, float size)
|
||||
{
|
||||
canvas->state->font_size = size;
|
||||
}
|
||||
|
||||
float plutovg_canvas_get_font_size(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
return canvas->state->font_size;
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_fill_rule(plutovg_canvas_t* canvas, plutovg_fill_rule_t winding)
|
||||
{
|
||||
canvas->state->winding = winding;
|
||||
}
|
||||
|
||||
plutovg_fill_rule_t plutovg_canvas_get_fill_rule(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
return canvas->state->winding;
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_operator(plutovg_canvas_t* canvas, plutovg_operator_t op)
|
||||
{
|
||||
canvas->state->op = op;
|
||||
}
|
||||
|
||||
plutovg_operator_t plutovg_canvas_get_operator(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
return canvas->state->op;
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_opacity(plutovg_canvas_t* canvas, float opacity)
|
||||
{
|
||||
canvas->state->opacity = plutovg_clamp(opacity, 0.f, 1.f);
|
||||
}
|
||||
|
||||
float plutovg_canvas_get_opacity(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
return canvas->state->opacity;
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_line_width(plutovg_canvas_t* canvas, float line_width)
|
||||
{
|
||||
canvas->state->stroke.style.width = line_width;
|
||||
}
|
||||
|
||||
float plutovg_canvas_get_line_width(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
return canvas->state->stroke.style.width;
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_line_cap(plutovg_canvas_t* canvas, plutovg_line_cap_t line_cap)
|
||||
{
|
||||
canvas->state->stroke.style.cap = line_cap;
|
||||
}
|
||||
|
||||
plutovg_line_cap_t plutovg_canvas_get_line_cap(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
return canvas->state->stroke.style.cap;
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_line_join(plutovg_canvas_t* canvas, plutovg_line_join_t line_join)
|
||||
{
|
||||
canvas->state->stroke.style.join = line_join;
|
||||
}
|
||||
|
||||
plutovg_line_join_t plutovg_canvas_get_line_join(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
return canvas->state->stroke.style.join;
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_miter_limit(plutovg_canvas_t* canvas, float miter_limit)
|
||||
{
|
||||
canvas->state->stroke.style.miter_limit = miter_limit;
|
||||
}
|
||||
|
||||
float plutovg_canvas_get_miter_limit(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
return canvas->state->stroke.style.miter_limit;
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_dash(plutovg_canvas_t* canvas, float offset, const float* dashes, int ndashes)
|
||||
{
|
||||
plutovg_canvas_set_dash_offset(canvas, offset);
|
||||
plutovg_canvas_set_dash_array(canvas, dashes, ndashes);
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_dash_offset(plutovg_canvas_t* canvas, float offset)
|
||||
{
|
||||
canvas->state->stroke.dash.offset = offset;
|
||||
}
|
||||
|
||||
float plutovg_canvas_get_dash_offset(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
return canvas->state->stroke.dash.offset;
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_dash_array(plutovg_canvas_t* canvas, const float* dashes, int ndashes)
|
||||
{
|
||||
plutovg_array_clear(canvas->state->stroke.dash.array);
|
||||
plutovg_array_append_data(canvas->state->stroke.dash.array, dashes, ndashes);
|
||||
}
|
||||
|
||||
int plutovg_canvas_get_dash_array(const plutovg_canvas_t* canvas, const float** dashes)
|
||||
{
|
||||
if(dashes)
|
||||
*dashes = canvas->state->stroke.dash.array.data;
|
||||
return canvas->state->stroke.dash.array.size;
|
||||
}
|
||||
|
||||
void plutovg_canvas_translate(plutovg_canvas_t* canvas, float tx, float ty)
|
||||
{
|
||||
plutovg_matrix_translate(&canvas->state->matrix, tx, ty);
|
||||
}
|
||||
|
||||
void plutovg_canvas_scale(plutovg_canvas_t* canvas, float sx, float sy)
|
||||
{
|
||||
plutovg_matrix_scale(&canvas->state->matrix, sx, sy);
|
||||
}
|
||||
|
||||
void plutovg_canvas_shear(plutovg_canvas_t* canvas, float shx, float shy)
|
||||
{
|
||||
plutovg_matrix_shear(&canvas->state->matrix, shx, shy);
|
||||
}
|
||||
|
||||
void plutovg_canvas_rotate(plutovg_canvas_t* canvas, float angle)
|
||||
{
|
||||
plutovg_matrix_rotate(&canvas->state->matrix, angle);
|
||||
}
|
||||
|
||||
void plutovg_canvas_transform(plutovg_canvas_t* canvas, const plutovg_matrix_t* matrix)
|
||||
{
|
||||
plutovg_matrix_multiply(&canvas->state->matrix, matrix, &canvas->state->matrix);
|
||||
}
|
||||
|
||||
void plutovg_canvas_reset_matrix(plutovg_canvas_t* canvas)
|
||||
{
|
||||
plutovg_matrix_init_identity(&canvas->state->matrix);
|
||||
}
|
||||
|
||||
void plutovg_canvas_set_matrix(plutovg_canvas_t* canvas, const plutovg_matrix_t* matrix)
|
||||
{
|
||||
canvas->state->matrix = matrix ? *matrix : PLUTOVG_IDENTITY_MATRIX;
|
||||
}
|
||||
|
||||
void plutovg_canvas_get_matrix(const plutovg_canvas_t* canvas, plutovg_matrix_t* matrix)
|
||||
{
|
||||
*matrix = canvas->state->matrix;
|
||||
}
|
||||
|
||||
void plutovg_canvas_map(const plutovg_canvas_t* canvas, float x, float y, float* xx, float* yy)
|
||||
{
|
||||
plutovg_matrix_map(&canvas->state->matrix, x, y, xx, yy);
|
||||
}
|
||||
|
||||
void plutovg_canvas_map_point(const plutovg_canvas_t* canvas, const plutovg_point_t* src, plutovg_point_t* dst)
|
||||
{
|
||||
plutovg_matrix_map_point(&canvas->state->matrix, src, dst);
|
||||
}
|
||||
|
||||
void plutovg_canvas_map_rect(const plutovg_canvas_t* canvas, const plutovg_rect_t* src, plutovg_rect_t* dst)
|
||||
{
|
||||
plutovg_matrix_map_rect(&canvas->state->matrix, src, dst);
|
||||
}
|
||||
|
||||
void plutovg_canvas_move_to(plutovg_canvas_t* canvas, float x, float y)
|
||||
{
|
||||
plutovg_path_move_to(canvas->path, x, y);
|
||||
}
|
||||
|
||||
void plutovg_canvas_line_to(plutovg_canvas_t* canvas, float x, float y)
|
||||
{
|
||||
plutovg_path_line_to(canvas->path, x, y);
|
||||
}
|
||||
|
||||
void plutovg_canvas_quad_to(plutovg_canvas_t* canvas, float x1, float y1, float x2, float y2)
|
||||
{
|
||||
plutovg_path_quad_to(canvas->path, x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
void plutovg_canvas_cubic_to(plutovg_canvas_t* canvas, float x1, float y1, float x2, float y2, float x3, float y3)
|
||||
{
|
||||
plutovg_path_cubic_to(canvas->path, x1, y1, x2, y2, x3, y3);
|
||||
}
|
||||
|
||||
void plutovg_canvas_arc_to(plutovg_canvas_t* canvas, float rx, float ry, float angle, bool large_arc_flag, bool sweep_flag, float x, float y)
|
||||
{
|
||||
plutovg_path_arc_to(canvas->path, rx, ry, angle, large_arc_flag, sweep_flag, x, y);
|
||||
}
|
||||
|
||||
void plutovg_canvas_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h)
|
||||
{
|
||||
plutovg_path_add_rect(canvas->path, x, y, w, h);
|
||||
}
|
||||
|
||||
void plutovg_canvas_round_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h, float rx, float ry)
|
||||
{
|
||||
plutovg_path_add_round_rect(canvas->path, x, y, w, h, rx, ry);
|
||||
}
|
||||
|
||||
void plutovg_canvas_ellipse(plutovg_canvas_t* canvas, float cx, float cy, float rx, float ry)
|
||||
{
|
||||
plutovg_path_add_ellipse(canvas->path, cx, cy, rx, ry);
|
||||
}
|
||||
|
||||
void plutovg_canvas_circle(plutovg_canvas_t* canvas, float cx, float cy, float r)
|
||||
{
|
||||
plutovg_path_add_circle(canvas->path, cx, cy, r);
|
||||
}
|
||||
|
||||
void plutovg_canvas_arc(plutovg_canvas_t* canvas, float cx, float cy, float r, float a0, float a1, bool ccw)
|
||||
{
|
||||
plutovg_path_add_arc(canvas->path, cx, cy, r, a0, a1, ccw);
|
||||
}
|
||||
|
||||
void plutovg_canvas_add_path(plutovg_canvas_t* canvas, const plutovg_path_t* path)
|
||||
{
|
||||
plutovg_path_add_path(canvas->path, path, NULL);
|
||||
}
|
||||
|
||||
void plutovg_canvas_new_path(plutovg_canvas_t* canvas)
|
||||
{
|
||||
plutovg_path_reset(canvas->path);
|
||||
}
|
||||
|
||||
void plutovg_canvas_close_path(plutovg_canvas_t* canvas)
|
||||
{
|
||||
plutovg_path_close(canvas->path);
|
||||
}
|
||||
|
||||
void plutovg_canvas_get_current_point(const plutovg_canvas_t* canvas, float* x, float* y)
|
||||
{
|
||||
plutovg_path_get_current_point(canvas->path, x, y);
|
||||
}
|
||||
|
||||
plutovg_path_t* plutovg_canvas_get_path(const plutovg_canvas_t* canvas)
|
||||
{
|
||||
return canvas->path;
|
||||
}
|
||||
|
||||
void plutovg_canvas_fill_extents(const plutovg_canvas_t* canvas, plutovg_rect_t* extents)
|
||||
{
|
||||
plutovg_path_extents(canvas->path, extents, true);
|
||||
plutovg_canvas_map_rect(canvas, extents, extents);
|
||||
}
|
||||
|
||||
void plutovg_canvas_stroke_extents(const plutovg_canvas_t* canvas, plutovg_rect_t* extents)
|
||||
{
|
||||
plutovg_stroke_data_t* stroke = &canvas->state->stroke;
|
||||
float cap_limit = stroke->style.width / 2.f;
|
||||
if(stroke->style.cap == PLUTOVG_LINE_CAP_SQUARE)
|
||||
cap_limit *= PLUTOVG_SQRT2;
|
||||
float join_limit = stroke->style.width / 2.f;
|
||||
if(stroke->style.join == PLUTOVG_LINE_JOIN_MITER) {
|
||||
join_limit *= stroke->style.miter_limit;
|
||||
}
|
||||
|
||||
float delta = plutovg_max(cap_limit, join_limit);
|
||||
plutovg_path_extents(canvas->path, extents, true);
|
||||
extents->x -= delta;
|
||||
extents->y -= delta;
|
||||
extents->w += delta * 2.f;
|
||||
extents->h += delta * 2.f;
|
||||
plutovg_canvas_map_rect(canvas, extents, extents);
|
||||
}
|
||||
|
||||
void plutovg_canvas_clip_extents(const plutovg_canvas_t* canvas, plutovg_rect_t* extents)
|
||||
{
|
||||
if(canvas->state->clipping) {
|
||||
plutovg_span_buffer_extents(&canvas->state->clip_spans, extents);
|
||||
} else {
|
||||
extents->x = canvas->clip_rect.x;
|
||||
extents->y = canvas->clip_rect.y;
|
||||
extents->w = canvas->clip_rect.w;
|
||||
extents->h = canvas->clip_rect.h;
|
||||
}
|
||||
}
|
||||
|
||||
void plutovg_canvas_fill(plutovg_canvas_t* canvas)
|
||||
{
|
||||
plutovg_canvas_fill_preserve(canvas);
|
||||
plutovg_canvas_new_path(canvas);
|
||||
}
|
||||
|
||||
void plutovg_canvas_stroke(plutovg_canvas_t* canvas)
|
||||
{
|
||||
plutovg_canvas_stroke_preserve(canvas);
|
||||
plutovg_canvas_new_path(canvas);
|
||||
}
|
||||
|
||||
void plutovg_canvas_clip(plutovg_canvas_t* canvas)
|
||||
{
|
||||
plutovg_canvas_clip_preserve(canvas);
|
||||
plutovg_canvas_new_path(canvas);
|
||||
}
|
||||
|
||||
void plutovg_canvas_paint(plutovg_canvas_t* canvas)
|
||||
{
|
||||
if(canvas->state->clipping) {
|
||||
plutovg_blend(canvas, &canvas->state->clip_spans);
|
||||
} else {
|
||||
plutovg_span_buffer_init_rect(&canvas->clip_spans, 0, 0, canvas->surface->width, canvas->surface->height);
|
||||
plutovg_blend(canvas, &canvas->clip_spans);
|
||||
}
|
||||
}
|
||||
|
||||
void plutovg_canvas_fill_preserve(plutovg_canvas_t* canvas)
|
||||
{
|
||||
plutovg_rasterize(&canvas->fill_spans, canvas->path, &canvas->state->matrix, &canvas->clip_rect, NULL, canvas->state->winding);
|
||||
if(canvas->state->clipping) {
|
||||
plutovg_span_buffer_intersect(&canvas->clip_spans, &canvas->fill_spans, &canvas->state->clip_spans);
|
||||
plutovg_blend(canvas, &canvas->clip_spans);
|
||||
} else {
|
||||
plutovg_blend(canvas, &canvas->fill_spans);
|
||||
}
|
||||
}
|
||||
|
||||
void plutovg_canvas_stroke_preserve(plutovg_canvas_t* canvas)
|
||||
{
|
||||
plutovg_rasterize(&canvas->fill_spans, canvas->path, &canvas->state->matrix, &canvas->clip_rect, &canvas->state->stroke, PLUTOVG_FILL_RULE_NON_ZERO);
|
||||
if(canvas->state->clipping) {
|
||||
plutovg_span_buffer_intersect(&canvas->clip_spans, &canvas->fill_spans, &canvas->state->clip_spans);
|
||||
plutovg_blend(canvas, &canvas->clip_spans);
|
||||
} else {
|
||||
plutovg_blend(canvas, &canvas->fill_spans);
|
||||
}
|
||||
}
|
||||
|
||||
void plutovg_canvas_clip_preserve(plutovg_canvas_t* canvas)
|
||||
{
|
||||
if(canvas->state->clipping) {
|
||||
plutovg_rasterize(&canvas->fill_spans, canvas->path, &canvas->state->matrix, &canvas->clip_rect, NULL, canvas->state->winding);
|
||||
plutovg_span_buffer_intersect(&canvas->clip_spans, &canvas->fill_spans, &canvas->state->clip_spans);
|
||||
plutovg_span_buffer_copy(&canvas->state->clip_spans, &canvas->clip_spans);
|
||||
} else {
|
||||
plutovg_rasterize(&canvas->state->clip_spans, canvas->path, &canvas->state->matrix, &canvas->clip_rect, NULL, canvas->state->winding);
|
||||
canvas->state->clipping = true;
|
||||
}
|
||||
}
|
||||
|
||||
void plutovg_canvas_fill_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h)
|
||||
{
|
||||
plutovg_canvas_new_path(canvas);
|
||||
plutovg_canvas_rect(canvas, x, y, w, h);
|
||||
plutovg_canvas_fill(canvas);
|
||||
}
|
||||
|
||||
void plutovg_canvas_fill_path(plutovg_canvas_t* canvas, const plutovg_path_t* path)
|
||||
{
|
||||
plutovg_canvas_new_path(canvas);
|
||||
plutovg_canvas_add_path(canvas, path);
|
||||
plutovg_canvas_fill(canvas);
|
||||
}
|
||||
|
||||
void plutovg_canvas_stroke_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h)
|
||||
{
|
||||
plutovg_canvas_new_path(canvas);
|
||||
plutovg_canvas_rect(canvas, x, y, w, h);
|
||||
plutovg_canvas_stroke(canvas);
|
||||
}
|
||||
|
||||
void plutovg_canvas_stroke_path(plutovg_canvas_t* canvas, const plutovg_path_t* path)
|
||||
{
|
||||
plutovg_canvas_new_path(canvas);
|
||||
plutovg_canvas_add_path(canvas, path);
|
||||
plutovg_canvas_stroke(canvas);
|
||||
}
|
||||
|
||||
void plutovg_canvas_clip_rect(plutovg_canvas_t* canvas, float x, float y, float w, float h)
|
||||
{
|
||||
plutovg_canvas_new_path(canvas);
|
||||
plutovg_canvas_rect(canvas, x, y, w, h);
|
||||
plutovg_canvas_clip(canvas);
|
||||
}
|
||||
|
||||
void plutovg_canvas_clip_path(plutovg_canvas_t* canvas, const plutovg_path_t* path)
|
||||
{
|
||||
plutovg_canvas_new_path(canvas);
|
||||
plutovg_canvas_add_path(canvas, path);
|
||||
plutovg_canvas_clip(canvas);
|
||||
}
|
||||
|
||||
float plutovg_canvas_add_glyph(plutovg_canvas_t* canvas, plutovg_codepoint_t codepoint, float x, float y)
|
||||
{
|
||||
plutovg_state_t* state = canvas->state;
|
||||
if(state->font_face && state->font_size > 0.f)
|
||||
return plutovg_font_face_get_glyph_path(state->font_face, state->font_size, x, y, codepoint, canvas->path);
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
float plutovg_canvas_add_text(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, float x, float y)
|
||||
{
|
||||
plutovg_state_t* state = canvas->state;
|
||||
if(state->font_face == NULL || state->font_size <= 0.f)
|
||||
return 0.f;
|
||||
plutovg_text_iterator_t it;
|
||||
plutovg_text_iterator_init(&it, text, length, encoding);
|
||||
float advance_width = 0.f;
|
||||
while(plutovg_text_iterator_has_next(&it)) {
|
||||
plutovg_codepoint_t codepoint = plutovg_text_iterator_next(&it);
|
||||
advance_width += plutovg_font_face_get_glyph_path(state->font_face, state->font_size, x + advance_width, y, codepoint, canvas->path);
|
||||
}
|
||||
|
||||
return advance_width;
|
||||
}
|
||||
|
||||
float plutovg_canvas_fill_text(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, float x, float y)
|
||||
{
|
||||
plutovg_canvas_new_path(canvas);
|
||||
float advance_width = plutovg_canvas_add_text(canvas, text, length, encoding, x, y);
|
||||
plutovg_canvas_fill(canvas);
|
||||
return advance_width;
|
||||
}
|
||||
|
||||
float plutovg_canvas_stroke_text(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, float x, float y)
|
||||
{
|
||||
plutovg_canvas_new_path(canvas);
|
||||
float advance_width = plutovg_canvas_add_text(canvas, text, length, encoding, x, y);
|
||||
plutovg_canvas_stroke(canvas);
|
||||
return advance_width;
|
||||
}
|
||||
|
||||
float plutovg_canvas_clip_text(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, float x, float y)
|
||||
{
|
||||
plutovg_canvas_new_path(canvas);
|
||||
float advance_width = plutovg_canvas_add_text(canvas, text, length, encoding, x, y);
|
||||
plutovg_canvas_clip(canvas);
|
||||
return advance_width;
|
||||
}
|
||||
|
||||
void plutovg_canvas_font_metrics(const plutovg_canvas_t* canvas, float* ascent, float* descent, float* line_gap, plutovg_rect_t* extents)
|
||||
{
|
||||
plutovg_state_t* state = canvas->state;
|
||||
if(state->font_face && state->font_size > 0.f) {
|
||||
plutovg_font_face_get_metrics(state->font_face, state->font_size, ascent, descent, line_gap, extents);
|
||||
return;
|
||||
}
|
||||
|
||||
if(ascent) *ascent = 0.f;
|
||||
if(descent) *descent = 0.f;
|
||||
if(line_gap) *line_gap = 0.f;
|
||||
if(extents) {
|
||||
extents->x = 0.f;
|
||||
extents->y = 0.f;
|
||||
extents->w = 0.f;
|
||||
extents->h = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
void plutovg_canvas_glyph_metrics(plutovg_canvas_t* canvas, plutovg_codepoint_t codepoint, float* advance_width, float* left_side_bearing, plutovg_rect_t* extents)
|
||||
{
|
||||
plutovg_state_t* state = canvas->state;
|
||||
if(state->font_face && state->font_size > 0.f) {
|
||||
plutovg_font_face_get_glyph_metrics(state->font_face, state->font_size, codepoint, advance_width, left_side_bearing, extents);
|
||||
return;
|
||||
}
|
||||
|
||||
if(advance_width) *advance_width = 0.f;
|
||||
if(left_side_bearing) *left_side_bearing = 0.f;
|
||||
if(extents) {
|
||||
extents->x = 0.f;
|
||||
extents->y = 0.f;
|
||||
extents->w = 0.f;
|
||||
extents->h = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
float plutovg_canvas_text_extents(plutovg_canvas_t* canvas, const void* text, int length, plutovg_text_encoding_t encoding, plutovg_rect_t* extents)
|
||||
{
|
||||
plutovg_state_t* state = canvas->state;
|
||||
if(state->font_face && state->font_size > 0.f) {
|
||||
return plutovg_font_face_text_extents(state->font_face, state->font_size, text, length, encoding, extents);
|
||||
}
|
||||
|
||||
if(extents) {
|
||||
extents->x = 0.f;
|
||||
extents->y = 0.f;
|
||||
extents->w = 0.f;
|
||||
extents->h = 0.f;
|
||||
}
|
||||
|
||||
return 0.f;
|
||||
}
|
||||
414
3rdparty/plutosvg/plutovg/source/plutovg-font.c
vendored
Normal file
414
3rdparty/plutosvg/plutovg/source/plutovg-font.c
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
#include "plutovg.h"
|
||||
#include "plutovg-utils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define STBTT_STATIC
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "plutovg-stb-truetype.h"
|
||||
|
||||
static int plutovg_text_iterator_length(const void* data, int length, plutovg_text_encoding_t encoding)
|
||||
{
|
||||
if(length != -1)
|
||||
return length;
|
||||
length = 0;
|
||||
switch(encoding) {
|
||||
case PLUTOVG_TEXT_ENCODING_UTF8:
|
||||
case PLUTOVG_TEXT_ENCODING_LATIN1: {
|
||||
const uint8_t* text = data;
|
||||
while(*text++)
|
||||
length++;
|
||||
break;
|
||||
} case PLUTOVG_TEXT_ENCODING_UTF16: {
|
||||
const uint16_t* text = data;
|
||||
while(*text++)
|
||||
length++;
|
||||
break;
|
||||
} case PLUTOVG_TEXT_ENCODING_UTF32: {
|
||||
const uint32_t* text = data;
|
||||
while(*text++)
|
||||
length++;
|
||||
break;
|
||||
} default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void plutovg_text_iterator_init(plutovg_text_iterator_t* it, const void* text, int length, plutovg_text_encoding_t encoding)
|
||||
{
|
||||
it->text = text;
|
||||
it->length = plutovg_text_iterator_length(text, length, encoding);
|
||||
it->encoding = encoding;
|
||||
it->index = 0;
|
||||
}
|
||||
|
||||
bool plutovg_text_iterator_has_next(const plutovg_text_iterator_t* it)
|
||||
{
|
||||
return it->index < it->length;
|
||||
}
|
||||
|
||||
plutovg_codepoint_t plutovg_text_iterator_next(plutovg_text_iterator_t* it)
|
||||
{
|
||||
plutovg_codepoint_t codepoint = 0;
|
||||
switch(it->encoding) {
|
||||
case PLUTOVG_TEXT_ENCODING_UTF8: {
|
||||
static const uint8_t trailing[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
|
||||
};
|
||||
|
||||
static const uint32_t offsets[6] = {
|
||||
0x00000000, 0x00003080, 0x000E2080, 0x03C82080, 0xFA082080, 0x82082080
|
||||
};
|
||||
|
||||
const uint8_t* text = it->text;
|
||||
int trailing_bytes = trailing[text[it->index]];
|
||||
if(it->index + trailing_bytes >= it->length)
|
||||
trailing_bytes = 0;
|
||||
switch(trailing_bytes) {
|
||||
case 5: codepoint += text[it->index++]; codepoint <<= 6;
|
||||
case 4: codepoint += text[it->index++]; codepoint <<= 6;
|
||||
case 3: codepoint += text[it->index++]; codepoint <<= 6;
|
||||
case 2: codepoint += text[it->index++]; codepoint <<= 6;
|
||||
case 1: codepoint += text[it->index++]; codepoint <<= 6;
|
||||
case 0: codepoint += text[it->index++];
|
||||
}
|
||||
|
||||
codepoint -= offsets[trailing_bytes];
|
||||
break;
|
||||
} case PLUTOVG_TEXT_ENCODING_UTF16: {
|
||||
const uint16_t* text = it->text;
|
||||
codepoint = text[it->index++];
|
||||
if(((codepoint) & 0xfffffc00) == 0xd800) {
|
||||
if(it->index < it->length && (((codepoint) & 0xfffffc00) == 0xdc00)) {
|
||||
uint16_t trail = text[it->index++];
|
||||
codepoint = (codepoint << 10) + trail - ((0xD800u << 10) - 0x10000u + 0xDC00u);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
} case PLUTOVG_TEXT_ENCODING_UTF32: {
|
||||
const uint32_t* text = it->text;
|
||||
codepoint = text[it->index++];
|
||||
break;
|
||||
} case PLUTOVG_TEXT_ENCODING_LATIN1: {
|
||||
const uint8_t* text = it->text;
|
||||
codepoint = text[it->index++];
|
||||
break;
|
||||
} default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return codepoint;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
stbtt_vertex* vertices;
|
||||
int nvertices;
|
||||
int index;
|
||||
int advance_width;
|
||||
int left_side_bearing;
|
||||
int x1;
|
||||
int y1;
|
||||
int x2;
|
||||
int y2;
|
||||
} glyph_t;
|
||||
|
||||
#define GLYPH_CACHE_SIZE 256
|
||||
struct plutovg_font_face {
|
||||
int ref_count;
|
||||
int ascent;
|
||||
int descent;
|
||||
int line_gap;
|
||||
int x1;
|
||||
int y1;
|
||||
int x2;
|
||||
int y2;
|
||||
stbtt_fontinfo info;
|
||||
glyph_t** glyphs[GLYPH_CACHE_SIZE];
|
||||
plutovg_destroy_func_t destroy_func;
|
||||
void* closure;
|
||||
};
|
||||
|
||||
plutovg_font_face_t* plutovg_font_face_load_from_file(const char* filename, int ttcindex)
|
||||
{
|
||||
FILE* fp = fopen(filename, "rb");
|
||||
if(fp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
long length = ftell(fp);
|
||||
if(length == -1L) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* data = malloc(length);
|
||||
if(data == NULL) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
size_t nread = fread(data, 1, length, fp);
|
||||
fclose(fp);
|
||||
|
||||
if(nread != length) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return plutovg_font_face_load_from_data(data, length, ttcindex, free, data);
|
||||
}
|
||||
|
||||
plutovg_font_face_t* plutovg_font_face_load_from_data(const void* data, unsigned int length, int ttcindex, plutovg_destroy_func_t destroy_func, void* closure)
|
||||
{
|
||||
stbtt_fontinfo info;
|
||||
int offset = stbtt_GetFontOffsetForIndex(data, ttcindex);
|
||||
if(offset == -1 || !stbtt_InitFont(&info, data, offset)) {
|
||||
if(destroy_func)
|
||||
destroy_func(closure);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
plutovg_font_face_t* face = malloc(sizeof(plutovg_font_face_t));
|
||||
face->ref_count = 1;
|
||||
face->info = info;
|
||||
stbtt_GetFontVMetrics(&face->info, &face->ascent, &face->descent, &face->line_gap);
|
||||
stbtt_GetFontBoundingBox(&face->info, &face->x1, &face->y1, &face->x2, &face->y2);
|
||||
memset(face->glyphs, 0, sizeof(face->glyphs));
|
||||
face->destroy_func = destroy_func;
|
||||
face->closure = closure;
|
||||
return face;
|
||||
}
|
||||
|
||||
plutovg_font_face_t* plutovg_font_face_reference(plutovg_font_face_t* face)
|
||||
{
|
||||
if(face == NULL)
|
||||
return NULL;
|
||||
++face->ref_count;
|
||||
return face;
|
||||
}
|
||||
|
||||
void plutovg_font_face_destroy(plutovg_font_face_t* face)
|
||||
{
|
||||
if(face == NULL)
|
||||
return;
|
||||
if(--face->ref_count == 0) {
|
||||
for(int i = 0; i < GLYPH_CACHE_SIZE; i++) {
|
||||
if(face->glyphs[i] == NULL)
|
||||
continue;
|
||||
for(int j = 0; j < GLYPH_CACHE_SIZE; j++) {
|
||||
glyph_t* glyph = face->glyphs[i][j];
|
||||
if(glyph == NULL)
|
||||
continue;
|
||||
stbtt_FreeShape(&face->info, glyph->vertices);
|
||||
free(glyph);
|
||||
}
|
||||
|
||||
free(face->glyphs[i]);
|
||||
}
|
||||
|
||||
if(face->destroy_func)
|
||||
face->destroy_func(face->closure);
|
||||
free(face);
|
||||
}
|
||||
}
|
||||
|
||||
int plutovg_font_face_get_reference_count(const plutovg_font_face_t* face)
|
||||
{
|
||||
if(face)
|
||||
return face->ref_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static float plutovg_font_face_get_scale(const plutovg_font_face_t* face, float size)
|
||||
{
|
||||
return stbtt_ScaleForMappingEmToPixels(&face->info, size);
|
||||
}
|
||||
|
||||
void plutovg_font_face_get_metrics(const plutovg_font_face_t* face, float size, float* ascent, float* descent, float* line_gap, plutovg_rect_t* extents)
|
||||
{
|
||||
float scale = plutovg_font_face_get_scale(face, size);
|
||||
if(ascent) *ascent = face->ascent * scale;
|
||||
if(descent) *descent = face->descent * scale;
|
||||
if(line_gap) *line_gap = face->line_gap * scale;
|
||||
if(extents) {
|
||||
extents->x = face->x1 * scale;
|
||||
extents->y = face->y2 * -scale;
|
||||
extents->w = (face->x2 - face->x1) * scale;
|
||||
extents->h = (face->y1 - face->y2) * -scale;
|
||||
}
|
||||
}
|
||||
|
||||
static glyph_t* plutovg_font_face_get_glyph(plutovg_font_face_t* face, plutovg_codepoint_t codepoint)
|
||||
{
|
||||
unsigned int msb = (codepoint >> 8) & 0xFF;
|
||||
if(face->glyphs[msb] == NULL) {
|
||||
face->glyphs[msb] = calloc(GLYPH_CACHE_SIZE, sizeof(glyph_t*));
|
||||
}
|
||||
|
||||
unsigned int lsb = codepoint & 0xFF;
|
||||
if(face->glyphs[msb][lsb] == NULL) {
|
||||
glyph_t* glyph = malloc(sizeof(glyph_t));
|
||||
glyph->index = stbtt_FindGlyphIndex(&face->info, codepoint);
|
||||
glyph->nvertices = stbtt_GetGlyphShape(&face->info, glyph->index, &glyph->vertices);
|
||||
stbtt_GetGlyphHMetrics(&face->info, glyph->index, &glyph->advance_width, &glyph->left_side_bearing);
|
||||
if(!stbtt_GetGlyphBox(&face->info, glyph->index, &glyph->x1, &glyph->y1, &glyph->x2, &glyph->y2))
|
||||
glyph->x1 = glyph->y1 = glyph->x2 = glyph->y2 = 0;
|
||||
face->glyphs[msb][lsb] = glyph;
|
||||
}
|
||||
|
||||
return face->glyphs[msb][lsb];
|
||||
}
|
||||
|
||||
void plutovg_font_face_get_glyph_metrics(plutovg_font_face_t* face, float size, plutovg_codepoint_t codepoint, float* advance_width, float* left_side_bearing, plutovg_rect_t* extents)
|
||||
{
|
||||
float scale = plutovg_font_face_get_scale(face, size);
|
||||
glyph_t* glyph = plutovg_font_face_get_glyph(face, codepoint);
|
||||
if(advance_width) *advance_width = glyph->advance_width * scale;
|
||||
if(left_side_bearing) *left_side_bearing = glyph->left_side_bearing * scale;
|
||||
if(extents) {
|
||||
extents->x = glyph->x1 * scale;
|
||||
extents->y = glyph->y2 * -scale;
|
||||
extents->w = (glyph->x2 - glyph->x1) * scale;
|
||||
extents->h = (glyph->y1 - glyph->y2) * -scale;
|
||||
}
|
||||
}
|
||||
|
||||
static void glyph_traverse_func(void* closure, plutovg_path_command_t command, const plutovg_point_t* points, int npoints)
|
||||
{
|
||||
plutovg_path_t* path = (plutovg_path_t*)(closure);
|
||||
switch(command) {
|
||||
case PLUTOVG_PATH_COMMAND_MOVE_TO:
|
||||
plutovg_path_move_to(path, points[0].x, points[0].y);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_LINE_TO:
|
||||
plutovg_path_line_to(path, points[0].x, points[0].y);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CUBIC_TO:
|
||||
plutovg_path_cubic_to(path, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CLOSE:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
float plutovg_font_face_get_glyph_path(plutovg_font_face_t* face, float size, float x, float y, plutovg_codepoint_t codepoint, plutovg_path_t* path)
|
||||
{
|
||||
return plutovg_font_face_traverse_glyph_path(face, size, x, y, codepoint, glyph_traverse_func, path);
|
||||
}
|
||||
|
||||
float plutovg_font_face_traverse_glyph_path(plutovg_font_face_t* face, float size, float x, float y, plutovg_codepoint_t codepoint, plutovg_path_traverse_func_t traverse_func, void* closure)
|
||||
{
|
||||
float scale = plutovg_font_face_get_scale(face, size);
|
||||
plutovg_matrix_t matrix;
|
||||
plutovg_matrix_init_translate(&matrix, x, y);
|
||||
plutovg_matrix_scale(&matrix, scale, -scale);
|
||||
|
||||
plutovg_point_t points[3];
|
||||
plutovg_point_t current_point = {0, 0};
|
||||
glyph_t* glyph = plutovg_font_face_get_glyph(face, codepoint);
|
||||
for(int i = 0; i < glyph->nvertices; i++) {
|
||||
switch(glyph->vertices[i].type) {
|
||||
case STBTT_vmove:
|
||||
points[0].x = glyph->vertices[i].x;
|
||||
points[0].y = glyph->vertices[i].y;
|
||||
current_point = points[0];
|
||||
plutovg_matrix_map_points(&matrix, points, points, 1);
|
||||
traverse_func(closure, PLUTOVG_PATH_COMMAND_MOVE_TO, points, 1);
|
||||
break;
|
||||
case STBTT_vline:
|
||||
points[0].x = glyph->vertices[i].x;
|
||||
points[0].y = glyph->vertices[i].y;
|
||||
current_point = points[0];
|
||||
plutovg_matrix_map_points(&matrix, points, points, 1);
|
||||
traverse_func(closure, PLUTOVG_PATH_COMMAND_LINE_TO, points, 1);
|
||||
break;
|
||||
case STBTT_vcurve:
|
||||
points[0].x = 2.f / 3.f * glyph->vertices[i].cx + 1.f / 3.f * current_point.x;
|
||||
points[0].y = 2.f / 3.f * glyph->vertices[i].cy + 1.f / 3.f * current_point.y;
|
||||
points[1].x = 2.f / 3.f * glyph->vertices[i].cx + 1.f / 3.f * glyph->vertices[i].x;
|
||||
points[1].y = 2.f / 3.f * glyph->vertices[i].cy + 1.f / 3.f * glyph->vertices[i].y;
|
||||
points[2].x = glyph->vertices[i].x;
|
||||
points[2].y = glyph->vertices[i].y;
|
||||
current_point = points[2];
|
||||
plutovg_matrix_map_points(&matrix, points, points, 3);
|
||||
traverse_func(closure, PLUTOVG_PATH_COMMAND_CUBIC_TO, points, 3);
|
||||
break;
|
||||
case STBTT_vcubic:
|
||||
points[0].x = glyph->vertices[i].cx;
|
||||
points[0].y = glyph->vertices[i].cy;
|
||||
points[1].x = glyph->vertices[i].cx1;
|
||||
points[1].y = glyph->vertices[i].cy1;
|
||||
points[2].x = glyph->vertices[i].x;
|
||||
points[2].y = glyph->vertices[i].y;
|
||||
current_point = points[2];
|
||||
plutovg_matrix_map_points(&matrix, points, points, 3);
|
||||
traverse_func(closure, PLUTOVG_PATH_COMMAND_CUBIC_TO, points, 3);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
return glyph->advance_width * scale;
|
||||
}
|
||||
|
||||
float plutovg_font_face_text_extents(plutovg_font_face_t* face, float size, const void* text, int length, plutovg_text_encoding_t encoding, plutovg_rect_t* extents)
|
||||
{
|
||||
plutovg_text_iterator_t it;
|
||||
plutovg_text_iterator_init(&it, text, length, encoding);
|
||||
plutovg_rect_t* text_extents = NULL;
|
||||
float total_advance_width = 0.f;
|
||||
while(plutovg_text_iterator_has_next(&it)) {
|
||||
plutovg_codepoint_t codepoint = plutovg_text_iterator_next(&it);
|
||||
|
||||
float advance_width;
|
||||
if(extents == NULL) {
|
||||
plutovg_font_face_get_glyph_metrics(face, size, codepoint, &advance_width, NULL, NULL);
|
||||
total_advance_width += advance_width;
|
||||
continue;
|
||||
}
|
||||
|
||||
plutovg_rect_t glyph_extents;
|
||||
plutovg_font_face_get_glyph_metrics(face, size, codepoint, &advance_width, NULL, &glyph_extents);
|
||||
|
||||
glyph_extents.x += total_advance_width;
|
||||
total_advance_width += advance_width;
|
||||
if(text_extents == NULL) {
|
||||
text_extents = extents;
|
||||
*text_extents = glyph_extents;
|
||||
continue;
|
||||
}
|
||||
|
||||
float x1 = plutovg_min(text_extents->x, glyph_extents.x);
|
||||
float y1 = plutovg_min(text_extents->y, glyph_extents.y);
|
||||
float x2 = plutovg_max(text_extents->x + text_extents->w, glyph_extents.x + glyph_extents.w);
|
||||
float y2 = plutovg_max(text_extents->y + text_extents->h, glyph_extents.y + glyph_extents.h);
|
||||
|
||||
text_extents->x = x1;
|
||||
text_extents->y = y1;
|
||||
text_extents->w = x2 - x1;
|
||||
text_extents->h = y2 - y1;
|
||||
}
|
||||
|
||||
if(extents && !text_extents) {
|
||||
extents->x = 0;
|
||||
extents->y = 0;
|
||||
extents->w = 0;
|
||||
extents->h = 0;
|
||||
}
|
||||
|
||||
return total_advance_width;
|
||||
}
|
||||
444
3rdparty/plutosvg/plutovg/source/plutovg-ft-math.c
vendored
Normal file
444
3rdparty/plutosvg/plutovg/source/plutovg-ft-math.c
vendored
Normal file
@@ -0,0 +1,444 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* fttrigon.c */
|
||||
/* */
|
||||
/* FreeType trigonometric functions (body). */
|
||||
/* */
|
||||
/* Copyright 2001-2005, 2012-2013 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* license, FTL.TXT. By continuing to use, modify, or distribute */
|
||||
/* this file you indicate that you have read the license and */
|
||||
/* understand and accept it fully. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
#include "plutovg-ft-math.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
static inline int clz(unsigned int x) {
|
||||
unsigned long r = 0;
|
||||
if (_BitScanReverse(&r, x))
|
||||
return 31 - r;
|
||||
return 32;
|
||||
}
|
||||
#define PVG_FT_MSB(x) (31 - clz(x))
|
||||
#elif defined(__GNUC__)
|
||||
#define PVG_FT_MSB(x) (31 - __builtin_clz(x))
|
||||
#else
|
||||
static inline int clz(unsigned int x) {
|
||||
int n = 0;
|
||||
if (x == 0) return 32;
|
||||
if (x <= 0x0000FFFFU) { n += 16; x <<= 16; }
|
||||
if (x <= 0x00FFFFFFU) { n += 8; x <<= 8; }
|
||||
if (x <= 0x0FFFFFFFU) { n += 4; x <<= 4; }
|
||||
if (x <= 0x3FFFFFFFU) { n += 2; x <<= 2; }
|
||||
if (x <= 0x7FFFFFFFU) { n += 1; }
|
||||
return n;
|
||||
}
|
||||
#define PVG_FT_MSB(x) (31 - clz(x))
|
||||
#endif
|
||||
|
||||
#define PVG_FT_PAD_FLOOR(x, n) ((x) & ~((n)-1))
|
||||
#define PVG_FT_PAD_ROUND(x, n) PVG_FT_PAD_FLOOR((x) + ((n) / 2), n)
|
||||
#define PVG_FT_PAD_CEIL(x, n) PVG_FT_PAD_FLOOR((x) + ((n)-1), n)
|
||||
|
||||
#define PVG_FT_BEGIN_STMNT do {
|
||||
#define PVG_FT_END_STMNT } while (0)
|
||||
|
||||
/* transfer sign leaving a positive number */
|
||||
#define PVG_FT_MOVE_SIGN(x, s) \
|
||||
PVG_FT_BEGIN_STMNT \
|
||||
if (x < 0) { \
|
||||
x = -x; \
|
||||
s = -s; \
|
||||
} \
|
||||
PVG_FT_END_STMNT
|
||||
|
||||
PVG_FT_Long PVG_FT_MulFix(PVG_FT_Long a, PVG_FT_Long b)
|
||||
{
|
||||
PVG_FT_Int s = 1;
|
||||
PVG_FT_Long c;
|
||||
|
||||
PVG_FT_MOVE_SIGN(a, s);
|
||||
PVG_FT_MOVE_SIGN(b, s);
|
||||
|
||||
c = (PVG_FT_Long)(((PVG_FT_Int64)a * b + 0x8000L) >> 16);
|
||||
|
||||
return (s > 0) ? c : -c;
|
||||
}
|
||||
|
||||
PVG_FT_Long PVG_FT_MulDiv(PVG_FT_Long a, PVG_FT_Long b, PVG_FT_Long c)
|
||||
{
|
||||
PVG_FT_Int s = 1;
|
||||
PVG_FT_Long d;
|
||||
|
||||
PVG_FT_MOVE_SIGN(a, s);
|
||||
PVG_FT_MOVE_SIGN(b, s);
|
||||
PVG_FT_MOVE_SIGN(c, s);
|
||||
|
||||
d = (PVG_FT_Long)(c > 0 ? ((PVG_FT_Int64)a * b + (c >> 1)) / c : 0x7FFFFFFFL);
|
||||
|
||||
return (s > 0) ? d : -d;
|
||||
}
|
||||
|
||||
PVG_FT_Long PVG_FT_DivFix(PVG_FT_Long a, PVG_FT_Long b)
|
||||
{
|
||||
PVG_FT_Int s = 1;
|
||||
PVG_FT_Long q;
|
||||
|
||||
PVG_FT_MOVE_SIGN(a, s);
|
||||
PVG_FT_MOVE_SIGN(b, s);
|
||||
|
||||
q = (PVG_FT_Long)(b > 0 ? (((PVG_FT_UInt64)a << 16) + (b >> 1)) / b
|
||||
: 0x7FFFFFFFL);
|
||||
|
||||
return (s < 0 ? -q : q);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* This is a fixed-point CORDIC implementation of trigonometric */
|
||||
/* functions as well as transformations between Cartesian and polar */
|
||||
/* coordinates. The angles are represented as 16.16 fixed-point values */
|
||||
/* in degrees, i.e., the angular resolution is 2^-16 degrees. Note that */
|
||||
/* only vectors longer than 2^16*180/pi (or at least 22 bits) on a */
|
||||
/* discrete Cartesian grid can have the same or better angular */
|
||||
/* resolution. Therefore, to maintain this precision, some functions */
|
||||
/* require an interim upscaling of the vectors, whereas others operate */
|
||||
/* with 24-bit long vectors directly. */
|
||||
/* */
|
||||
/*************************************************************************/
|
||||
|
||||
/* the Cordic shrink factor 0.858785336480436 * 2^32 */
|
||||
#define PVG_FT_TRIG_SCALE 0xDBD95B16UL
|
||||
|
||||
/* the highest bit in overflow-safe vector components, */
|
||||
/* MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */
|
||||
#define PVG_FT_TRIG_SAFE_MSB 29
|
||||
|
||||
/* this table was generated for PVG_FT_PI = 180L << 16, i.e. degrees */
|
||||
#define PVG_FT_TRIG_MAX_ITERS 23
|
||||
|
||||
static const PVG_FT_Fixed ft_trig_arctan_table[] = {
|
||||
1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, 14668L,
|
||||
7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, 57L,
|
||||
29L, 14L, 7L, 4L, 2L, 1L};
|
||||
|
||||
/* multiply a given value by the CORDIC shrink factor */
|
||||
static PVG_FT_Fixed ft_trig_downscale(PVG_FT_Fixed val)
|
||||
{
|
||||
PVG_FT_Fixed s;
|
||||
PVG_FT_Int64 v;
|
||||
|
||||
s = val;
|
||||
val = PVG_FT_ABS(val);
|
||||
|
||||
v = (val * (PVG_FT_Int64)PVG_FT_TRIG_SCALE) + 0x100000000UL;
|
||||
val = (PVG_FT_Fixed)(v >> 32);
|
||||
|
||||
return (s >= 0) ? val : -val;
|
||||
}
|
||||
|
||||
/* undefined and never called for zero vector */
|
||||
static PVG_FT_Int ft_trig_prenorm(PVG_FT_Vector* vec)
|
||||
{
|
||||
PVG_FT_Pos x, y;
|
||||
PVG_FT_Int shift;
|
||||
|
||||
x = vec->x;
|
||||
y = vec->y;
|
||||
|
||||
shift = PVG_FT_MSB(PVG_FT_ABS(x) | PVG_FT_ABS(y));
|
||||
|
||||
if (shift <= PVG_FT_TRIG_SAFE_MSB) {
|
||||
shift = PVG_FT_TRIG_SAFE_MSB - shift;
|
||||
vec->x = (PVG_FT_Pos)((PVG_FT_ULong)x << shift);
|
||||
vec->y = (PVG_FT_Pos)((PVG_FT_ULong)y << shift);
|
||||
} else {
|
||||
shift -= PVG_FT_TRIG_SAFE_MSB;
|
||||
vec->x = x >> shift;
|
||||
vec->y = y >> shift;
|
||||
shift = -shift;
|
||||
}
|
||||
|
||||
return shift;
|
||||
}
|
||||
|
||||
static void ft_trig_pseudo_rotate(PVG_FT_Vector* vec, PVG_FT_Angle theta)
|
||||
{
|
||||
PVG_FT_Int i;
|
||||
PVG_FT_Fixed x, y, xtemp, b;
|
||||
const PVG_FT_Fixed* arctanptr;
|
||||
|
||||
x = vec->x;
|
||||
y = vec->y;
|
||||
|
||||
/* Rotate inside [-PI/4,PI/4] sector */
|
||||
while (theta < -PVG_FT_ANGLE_PI4) {
|
||||
xtemp = y;
|
||||
y = -x;
|
||||
x = xtemp;
|
||||
theta += PVG_FT_ANGLE_PI2;
|
||||
}
|
||||
|
||||
while (theta > PVG_FT_ANGLE_PI4) {
|
||||
xtemp = -y;
|
||||
y = x;
|
||||
x = xtemp;
|
||||
theta -= PVG_FT_ANGLE_PI2;
|
||||
}
|
||||
|
||||
arctanptr = ft_trig_arctan_table;
|
||||
|
||||
/* Pseudorotations, with right shifts */
|
||||
for (i = 1, b = 1; i < PVG_FT_TRIG_MAX_ITERS; b <<= 1, i++) {
|
||||
PVG_FT_Fixed v1 = ((y + b) >> i);
|
||||
PVG_FT_Fixed v2 = ((x + b) >> i);
|
||||
if (theta < 0) {
|
||||
xtemp = x + v1;
|
||||
y = y - v2;
|
||||
x = xtemp;
|
||||
theta += *arctanptr++;
|
||||
} else {
|
||||
xtemp = x - v1;
|
||||
y = y + v2;
|
||||
x = xtemp;
|
||||
theta -= *arctanptr++;
|
||||
}
|
||||
}
|
||||
|
||||
vec->x = x;
|
||||
vec->y = y;
|
||||
}
|
||||
|
||||
static void ft_trig_pseudo_polarize(PVG_FT_Vector* vec)
|
||||
{
|
||||
PVG_FT_Angle theta;
|
||||
PVG_FT_Int i;
|
||||
PVG_FT_Fixed x, y, xtemp, b;
|
||||
const PVG_FT_Fixed* arctanptr;
|
||||
|
||||
x = vec->x;
|
||||
y = vec->y;
|
||||
|
||||
/* Get the vector into [-PI/4,PI/4] sector */
|
||||
if (y > x) {
|
||||
if (y > -x) {
|
||||
theta = PVG_FT_ANGLE_PI2;
|
||||
xtemp = y;
|
||||
y = -x;
|
||||
x = xtemp;
|
||||
} else {
|
||||
theta = y > 0 ? PVG_FT_ANGLE_PI : -PVG_FT_ANGLE_PI;
|
||||
x = -x;
|
||||
y = -y;
|
||||
}
|
||||
} else {
|
||||
if (y < -x) {
|
||||
theta = -PVG_FT_ANGLE_PI2;
|
||||
xtemp = -y;
|
||||
y = x;
|
||||
x = xtemp;
|
||||
} else {
|
||||
theta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
arctanptr = ft_trig_arctan_table;
|
||||
|
||||
/* Pseudorotations, with right shifts */
|
||||
for (i = 1, b = 1; i < PVG_FT_TRIG_MAX_ITERS; b <<= 1, i++) {
|
||||
PVG_FT_Fixed v1 = ((y + b) >> i);
|
||||
PVG_FT_Fixed v2 = ((x + b) >> i);
|
||||
if (y > 0) {
|
||||
xtemp = x + v1;
|
||||
y = y - v2;
|
||||
x = xtemp;
|
||||
theta += *arctanptr++;
|
||||
} else {
|
||||
xtemp = x - v1;
|
||||
y = y + v2;
|
||||
x = xtemp;
|
||||
theta -= *arctanptr++;
|
||||
}
|
||||
}
|
||||
|
||||
/* round theta */
|
||||
if (theta >= 0)
|
||||
theta = PVG_FT_PAD_ROUND(theta, 32);
|
||||
else
|
||||
theta = -PVG_FT_PAD_ROUND(-theta, 32);
|
||||
|
||||
vec->x = x;
|
||||
vec->y = theta;
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
PVG_FT_Fixed PVG_FT_Cos(PVG_FT_Angle angle)
|
||||
{
|
||||
PVG_FT_Vector v;
|
||||
|
||||
v.x = PVG_FT_TRIG_SCALE >> 8;
|
||||
v.y = 0;
|
||||
ft_trig_pseudo_rotate(&v, angle);
|
||||
|
||||
return (v.x + 0x80L) >> 8;
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
PVG_FT_Fixed PVG_FT_Sin(PVG_FT_Angle angle)
|
||||
{
|
||||
return PVG_FT_Cos(PVG_FT_ANGLE_PI2 - angle);
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
PVG_FT_Fixed PVG_FT_Tan(PVG_FT_Angle angle)
|
||||
{
|
||||
PVG_FT_Vector v;
|
||||
|
||||
v.x = PVG_FT_TRIG_SCALE >> 8;
|
||||
v.y = 0;
|
||||
ft_trig_pseudo_rotate(&v, angle);
|
||||
|
||||
return PVG_FT_DivFix(v.y, v.x);
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
PVG_FT_Angle PVG_FT_Atan2(PVG_FT_Fixed dx, PVG_FT_Fixed dy)
|
||||
{
|
||||
PVG_FT_Vector v;
|
||||
|
||||
if (dx == 0 && dy == 0) return 0;
|
||||
|
||||
v.x = dx;
|
||||
v.y = dy;
|
||||
ft_trig_prenorm(&v);
|
||||
ft_trig_pseudo_polarize(&v);
|
||||
|
||||
return v.y;
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
void PVG_FT_Vector_Unit(PVG_FT_Vector* vec, PVG_FT_Angle angle)
|
||||
{
|
||||
vec->x = PVG_FT_TRIG_SCALE >> 8;
|
||||
vec->y = 0;
|
||||
ft_trig_pseudo_rotate(vec, angle);
|
||||
vec->x = (vec->x + 0x80L) >> 8;
|
||||
vec->y = (vec->y + 0x80L) >> 8;
|
||||
}
|
||||
|
||||
void PVG_FT_Vector_Rotate(PVG_FT_Vector* vec, PVG_FT_Angle angle)
|
||||
{
|
||||
PVG_FT_Int shift;
|
||||
PVG_FT_Vector v = *vec;
|
||||
|
||||
if ( v.x == 0 && v.y == 0 )
|
||||
return;
|
||||
|
||||
shift = ft_trig_prenorm( &v );
|
||||
ft_trig_pseudo_rotate( &v, angle );
|
||||
v.x = ft_trig_downscale( v.x );
|
||||
v.y = ft_trig_downscale( v.y );
|
||||
|
||||
if ( shift > 0 )
|
||||
{
|
||||
PVG_FT_Int32 half = (PVG_FT_Int32)1L << ( shift - 1 );
|
||||
|
||||
|
||||
vec->x = ( v.x + half - ( v.x < 0 ) ) >> shift;
|
||||
vec->y = ( v.y + half - ( v.y < 0 ) ) >> shift;
|
||||
}
|
||||
else
|
||||
{
|
||||
shift = -shift;
|
||||
vec->x = (PVG_FT_Pos)( (PVG_FT_ULong)v.x << shift );
|
||||
vec->y = (PVG_FT_Pos)( (PVG_FT_ULong)v.y << shift );
|
||||
}
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
PVG_FT_Fixed PVG_FT_Vector_Length(PVG_FT_Vector* vec)
|
||||
{
|
||||
PVG_FT_Int shift;
|
||||
PVG_FT_Vector v;
|
||||
|
||||
v = *vec;
|
||||
|
||||
/* handle trivial cases */
|
||||
if (v.x == 0) {
|
||||
return PVG_FT_ABS(v.y);
|
||||
} else if (v.y == 0) {
|
||||
return PVG_FT_ABS(v.x);
|
||||
}
|
||||
|
||||
/* general case */
|
||||
shift = ft_trig_prenorm(&v);
|
||||
ft_trig_pseudo_polarize(&v);
|
||||
|
||||
v.x = ft_trig_downscale(v.x);
|
||||
|
||||
if (shift > 0) return (v.x + (1 << (shift - 1))) >> shift;
|
||||
|
||||
return (PVG_FT_Fixed)((PVG_FT_UInt32)v.x << -shift);
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
void PVG_FT_Vector_Polarize(PVG_FT_Vector* vec, PVG_FT_Fixed* length,
|
||||
PVG_FT_Angle* angle)
|
||||
{
|
||||
PVG_FT_Int shift;
|
||||
PVG_FT_Vector v;
|
||||
|
||||
v = *vec;
|
||||
|
||||
if (v.x == 0 && v.y == 0) return;
|
||||
|
||||
shift = ft_trig_prenorm(&v);
|
||||
ft_trig_pseudo_polarize(&v);
|
||||
|
||||
v.x = ft_trig_downscale(v.x);
|
||||
|
||||
*length = (shift >= 0) ? (v.x >> shift)
|
||||
: (PVG_FT_Fixed)((PVG_FT_UInt32)v.x << -shift);
|
||||
*angle = v.y;
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
void PVG_FT_Vector_From_Polar(PVG_FT_Vector* vec, PVG_FT_Fixed length,
|
||||
PVG_FT_Angle angle)
|
||||
{
|
||||
vec->x = length;
|
||||
vec->y = 0;
|
||||
|
||||
PVG_FT_Vector_Rotate(vec, angle);
|
||||
}
|
||||
|
||||
/* documentation is in fttrigon.h */
|
||||
|
||||
PVG_FT_Angle PVG_FT_Angle_Diff( PVG_FT_Angle angle1, PVG_FT_Angle angle2 )
|
||||
{
|
||||
PVG_FT_Angle delta = angle2 - angle1;
|
||||
|
||||
while ( delta <= -PVG_FT_ANGLE_PI )
|
||||
delta += PVG_FT_ANGLE_2PI;
|
||||
|
||||
while ( delta > PVG_FT_ANGLE_PI )
|
||||
delta -= PVG_FT_ANGLE_2PI;
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
/* END */
|
||||
436
3rdparty/plutosvg/plutovg/source/plutovg-ft-math.h
vendored
Normal file
436
3rdparty/plutosvg/plutovg/source/plutovg-ft-math.h
vendored
Normal file
@@ -0,0 +1,436 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* fttrigon.h */
|
||||
/* */
|
||||
/* FreeType trigonometric functions (specification). */
|
||||
/* */
|
||||
/* Copyright 2001, 2003, 2005, 2007, 2013 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* license, FTL.TXT. By continuing to use, modify, or distribute */
|
||||
/* this file you indicate that you have read the license and */
|
||||
/* understand and accept it fully. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
#ifndef PLUTOVG_FT_MATH_H
|
||||
#define PLUTOVG_FT_MATH_H
|
||||
|
||||
#include "plutovg-ft-types.h"
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* The min and max functions missing in C. As usual, be careful not to */
|
||||
/* write things like PVG_FT_MIN( a++, b++ ) to avoid side effects. */
|
||||
/* */
|
||||
#define PVG_FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) )
|
||||
#define PVG_FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) )
|
||||
|
||||
#define PVG_FT_ABS( a ) ( (a) < 0 ? -(a) : (a) )
|
||||
|
||||
/*
|
||||
* Approximate sqrt(x*x+y*y) using the `alpha max plus beta min'
|
||||
* algorithm. We use alpha = 1, beta = 3/8, giving us results with a
|
||||
* largest error less than 7% compared to the exact value.
|
||||
*/
|
||||
#define PVG_FT_HYPOT( x, y ) \
|
||||
( x = PVG_FT_ABS( x ), \
|
||||
y = PVG_FT_ABS( y ), \
|
||||
x > y ? x + ( 3 * y >> 3 ) \
|
||||
: y + ( 3 * x >> 3 ) )
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* PVG_FT_MulFix */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A very simple function used to perform the computation */
|
||||
/* `(a*b)/0x10000' with maximum accuracy. Most of the time this is */
|
||||
/* used to multiply a given value by a 16.16 fixed-point factor. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* a :: The first multiplier. */
|
||||
/* b :: The second multiplier. Use a 16.16 factor here whenever */
|
||||
/* possible (see note below). */
|
||||
/* */
|
||||
/* <Return> */
|
||||
/* The result of `(a*b)/0x10000'. */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* This function has been optimized for the case where the absolute */
|
||||
/* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */
|
||||
/* As this happens mainly when scaling from notional units to */
|
||||
/* fractional pixels in FreeType, it resulted in noticeable speed */
|
||||
/* improvements between versions 2.x and 1.x. */
|
||||
/* */
|
||||
/* As a conclusion, always try to place a 16.16 factor as the */
|
||||
/* _second_ argument of this function; this can make a great */
|
||||
/* difference. */
|
||||
/* */
|
||||
PVG_FT_Long
|
||||
PVG_FT_MulFix( PVG_FT_Long a,
|
||||
PVG_FT_Long b );
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* PVG_FT_MulDiv */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A very simple function used to perform the computation `(a*b)/c' */
|
||||
/* with maximum accuracy (it uses a 64-bit intermediate integer */
|
||||
/* whenever necessary). */
|
||||
/* */
|
||||
/* This function isn't necessarily as fast as some processor specific */
|
||||
/* operations, but is at least completely portable. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* a :: The first multiplier. */
|
||||
/* b :: The second multiplier. */
|
||||
/* c :: The divisor. */
|
||||
/* */
|
||||
/* <Return> */
|
||||
/* The result of `(a*b)/c'. This function never traps when trying to */
|
||||
/* divide by zero; it simply returns `MaxInt' or `MinInt' depending */
|
||||
/* on the signs of `a' and `b'. */
|
||||
/* */
|
||||
PVG_FT_Long
|
||||
PVG_FT_MulDiv( PVG_FT_Long a,
|
||||
PVG_FT_Long b,
|
||||
PVG_FT_Long c );
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* PVG_FT_DivFix */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A very simple function used to perform the computation */
|
||||
/* `(a*0x10000)/b' with maximum accuracy. Most of the time, this is */
|
||||
/* used to divide a given value by a 16.16 fixed-point factor. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* a :: The numerator. */
|
||||
/* b :: The denominator. Use a 16.16 factor here. */
|
||||
/* */
|
||||
/* <Return> */
|
||||
/* The result of `(a*0x10000)/b'. */
|
||||
/* */
|
||||
PVG_FT_Long
|
||||
PVG_FT_DivFix( PVG_FT_Long a,
|
||||
PVG_FT_Long b );
|
||||
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Section> */
|
||||
/* computations */
|
||||
/* */
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @type:
|
||||
* PVG_FT_Angle
|
||||
*
|
||||
* @description:
|
||||
* This type is used to model angle values in FreeType. Note that the
|
||||
* angle is a 16.16 fixed-point value expressed in degrees.
|
||||
*
|
||||
*/
|
||||
typedef PVG_FT_Fixed PVG_FT_Angle;
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @macro:
|
||||
* PVG_FT_ANGLE_PI
|
||||
*
|
||||
* @description:
|
||||
* The angle pi expressed in @PVG_FT_Angle units.
|
||||
*
|
||||
*/
|
||||
#define PVG_FT_ANGLE_PI ( 180L << 16 )
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @macro:
|
||||
* PVG_FT_ANGLE_2PI
|
||||
*
|
||||
* @description:
|
||||
* The angle 2*pi expressed in @PVG_FT_Angle units.
|
||||
*
|
||||
*/
|
||||
#define PVG_FT_ANGLE_2PI ( PVG_FT_ANGLE_PI * 2 )
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @macro:
|
||||
* PVG_FT_ANGLE_PI2
|
||||
*
|
||||
* @description:
|
||||
* The angle pi/2 expressed in @PVG_FT_Angle units.
|
||||
*
|
||||
*/
|
||||
#define PVG_FT_ANGLE_PI2 ( PVG_FT_ANGLE_PI / 2 )
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @macro:
|
||||
* PVG_FT_ANGLE_PI4
|
||||
*
|
||||
* @description:
|
||||
* The angle pi/4 expressed in @PVG_FT_Angle units.
|
||||
*
|
||||
*/
|
||||
#define PVG_FT_ANGLE_PI4 ( PVG_FT_ANGLE_PI / 4 )
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Sin
|
||||
*
|
||||
* @description:
|
||||
* Return the sinus of a given angle in fixed-point format.
|
||||
*
|
||||
* @input:
|
||||
* angle ::
|
||||
* The input angle.
|
||||
*
|
||||
* @return:
|
||||
* The sinus value.
|
||||
*
|
||||
* @note:
|
||||
* If you need both the sinus and cosinus for a given angle, use the
|
||||
* function @PVG_FT_Vector_Unit.
|
||||
*
|
||||
*/
|
||||
PVG_FT_Fixed
|
||||
PVG_FT_Sin( PVG_FT_Angle angle );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Cos
|
||||
*
|
||||
* @description:
|
||||
* Return the cosinus of a given angle in fixed-point format.
|
||||
*
|
||||
* @input:
|
||||
* angle ::
|
||||
* The input angle.
|
||||
*
|
||||
* @return:
|
||||
* The cosinus value.
|
||||
*
|
||||
* @note:
|
||||
* If you need both the sinus and cosinus for a given angle, use the
|
||||
* function @PVG_FT_Vector_Unit.
|
||||
*
|
||||
*/
|
||||
PVG_FT_Fixed
|
||||
PVG_FT_Cos( PVG_FT_Angle angle );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Tan
|
||||
*
|
||||
* @description:
|
||||
* Return the tangent of a given angle in fixed-point format.
|
||||
*
|
||||
* @input:
|
||||
* angle ::
|
||||
* The input angle.
|
||||
*
|
||||
* @return:
|
||||
* The tangent value.
|
||||
*
|
||||
*/
|
||||
PVG_FT_Fixed
|
||||
PVG_FT_Tan( PVG_FT_Angle angle );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Atan2
|
||||
*
|
||||
* @description:
|
||||
* Return the arc-tangent corresponding to a given vector (x,y) in
|
||||
* the 2d plane.
|
||||
*
|
||||
* @input:
|
||||
* x ::
|
||||
* The horizontal vector coordinate.
|
||||
*
|
||||
* y ::
|
||||
* The vertical vector coordinate.
|
||||
*
|
||||
* @return:
|
||||
* The arc-tangent value (i.e. angle).
|
||||
*
|
||||
*/
|
||||
PVG_FT_Angle
|
||||
PVG_FT_Atan2( PVG_FT_Fixed x,
|
||||
PVG_FT_Fixed y );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Angle_Diff
|
||||
*
|
||||
* @description:
|
||||
* Return the difference between two angles. The result is always
|
||||
* constrained to the ]-PI..PI] interval.
|
||||
*
|
||||
* @input:
|
||||
* angle1 ::
|
||||
* First angle.
|
||||
*
|
||||
* angle2 ::
|
||||
* Second angle.
|
||||
*
|
||||
* @return:
|
||||
* Constrained value of `value2-value1'.
|
||||
*
|
||||
*/
|
||||
PVG_FT_Angle
|
||||
PVG_FT_Angle_Diff( PVG_FT_Angle angle1,
|
||||
PVG_FT_Angle angle2 );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Vector_Unit
|
||||
*
|
||||
* @description:
|
||||
* Return the unit vector corresponding to a given angle. After the
|
||||
* call, the value of `vec.x' will be `sin(angle)', and the value of
|
||||
* `vec.y' will be `cos(angle)'.
|
||||
*
|
||||
* This function is useful to retrieve both the sinus and cosinus of a
|
||||
* given angle quickly.
|
||||
*
|
||||
* @output:
|
||||
* vec ::
|
||||
* The address of target vector.
|
||||
*
|
||||
* @input:
|
||||
* angle ::
|
||||
* The input angle.
|
||||
*
|
||||
*/
|
||||
void
|
||||
PVG_FT_Vector_Unit( PVG_FT_Vector* vec,
|
||||
PVG_FT_Angle angle );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Vector_Rotate
|
||||
*
|
||||
* @description:
|
||||
* Rotate a vector by a given angle.
|
||||
*
|
||||
* @inout:
|
||||
* vec ::
|
||||
* The address of target vector.
|
||||
*
|
||||
* @input:
|
||||
* angle ::
|
||||
* The input angle.
|
||||
*
|
||||
*/
|
||||
void
|
||||
PVG_FT_Vector_Rotate( PVG_FT_Vector* vec,
|
||||
PVG_FT_Angle angle );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Vector_Length
|
||||
*
|
||||
* @description:
|
||||
* Return the length of a given vector.
|
||||
*
|
||||
* @input:
|
||||
* vec ::
|
||||
* The address of target vector.
|
||||
*
|
||||
* @return:
|
||||
* The vector length, expressed in the same units that the original
|
||||
* vector coordinates.
|
||||
*
|
||||
*/
|
||||
PVG_FT_Fixed
|
||||
PVG_FT_Vector_Length( PVG_FT_Vector* vec );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Vector_Polarize
|
||||
*
|
||||
* @description:
|
||||
* Compute both the length and angle of a given vector.
|
||||
*
|
||||
* @input:
|
||||
* vec ::
|
||||
* The address of source vector.
|
||||
*
|
||||
* @output:
|
||||
* length ::
|
||||
* The vector length.
|
||||
*
|
||||
* angle ::
|
||||
* The vector angle.
|
||||
*
|
||||
*/
|
||||
void
|
||||
PVG_FT_Vector_Polarize( PVG_FT_Vector* vec,
|
||||
PVG_FT_Fixed *length,
|
||||
PVG_FT_Angle *angle );
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Vector_From_Polar
|
||||
*
|
||||
* @description:
|
||||
* Compute vector coordinates from a length and angle.
|
||||
*
|
||||
* @output:
|
||||
* vec ::
|
||||
* The address of source vector.
|
||||
*
|
||||
* @input:
|
||||
* length ::
|
||||
* The vector length.
|
||||
*
|
||||
* angle ::
|
||||
* The vector angle.
|
||||
*
|
||||
*/
|
||||
void
|
||||
PVG_FT_Vector_From_Polar( PVG_FT_Vector* vec,
|
||||
PVG_FT_Fixed length,
|
||||
PVG_FT_Angle angle );
|
||||
|
||||
#endif /* PLUTOVG_FT_MATH_H */
|
||||
1706
3rdparty/plutosvg/plutovg/source/plutovg-ft-raster.c
vendored
Normal file
1706
3rdparty/plutosvg/plutovg/source/plutovg-ft-raster.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
420
3rdparty/plutosvg/plutovg/source/plutovg-ft-raster.h
vendored
Normal file
420
3rdparty/plutosvg/plutovg/source/plutovg-ft-raster.h
vendored
Normal file
@@ -0,0 +1,420 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* ftimage.h */
|
||||
/* */
|
||||
/* FreeType glyph image formats and default raster interface */
|
||||
/* (specification). */
|
||||
/* */
|
||||
/* Copyright 1996-2010, 2013 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* license, FTL.TXT. By continuing to use, modify, or distribute */
|
||||
/* this file you indicate that you have read the license and */
|
||||
/* understand and accept it fully. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
#ifndef PLUTOVG_FT_RASTER_H
|
||||
#define PLUTOVG_FT_RASTER_H
|
||||
|
||||
#include "plutovg-ft-types.h"
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* FT_BBox */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A structure used to hold an outline's bounding box, i.e., the */
|
||||
/* coordinates of its extrema in the horizontal and vertical */
|
||||
/* directions. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* xMin :: The horizontal minimum (left-most). */
|
||||
/* */
|
||||
/* yMin :: The vertical minimum (bottom-most). */
|
||||
/* */
|
||||
/* xMax :: The horizontal maximum (right-most). */
|
||||
/* */
|
||||
/* yMax :: The vertical maximum (top-most). */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* The bounding box is specified with the coordinates of the lower */
|
||||
/* left and the upper right corner. In PostScript, those values are */
|
||||
/* often called (llx,lly) and (urx,ury), respectively. */
|
||||
/* */
|
||||
/* If `yMin' is negative, this value gives the glyph's descender. */
|
||||
/* Otherwise, the glyph doesn't descend below the baseline. */
|
||||
/* Similarly, if `ymax' is positive, this value gives the glyph's */
|
||||
/* ascender. */
|
||||
/* */
|
||||
/* `xMin' gives the horizontal distance from the glyph's origin to */
|
||||
/* the left edge of the glyph's bounding box. If `xMin' is negative, */
|
||||
/* the glyph extends to the left of the origin. */
|
||||
/* */
|
||||
typedef struct PVG_FT_BBox_
|
||||
{
|
||||
PVG_FT_Pos xMin, yMin;
|
||||
PVG_FT_Pos xMax, yMax;
|
||||
|
||||
} PVG_FT_BBox;
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* PVG_FT_Outline */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* This structure is used to describe an outline to the scan-line */
|
||||
/* converter. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* n_contours :: The number of contours in the outline. */
|
||||
/* */
|
||||
/* n_points :: The number of points in the outline. */
|
||||
/* */
|
||||
/* points :: A pointer to an array of `n_points' @PVG_FT_Vector */
|
||||
/* elements, giving the outline's point coordinates. */
|
||||
/* */
|
||||
/* tags :: A pointer to an array of `n_points' chars, giving */
|
||||
/* each outline point's type. */
|
||||
/* */
|
||||
/* If bit~0 is unset, the point is `off' the curve, */
|
||||
/* i.e., a Bézier control point, while it is `on' if */
|
||||
/* set. */
|
||||
/* */
|
||||
/* Bit~1 is meaningful for `off' points only. If set, */
|
||||
/* it indicates a third-order Bézier arc control point; */
|
||||
/* and a second-order control point if unset. */
|
||||
/* */
|
||||
/* If bit~2 is set, bits 5-7 contain the drop-out mode */
|
||||
/* (as defined in the OpenType specification; the value */
|
||||
/* is the same as the argument to the SCANMODE */
|
||||
/* instruction). */
|
||||
/* */
|
||||
/* Bits 3 and~4 are reserved for internal purposes. */
|
||||
/* */
|
||||
/* contours :: An array of `n_contours' shorts, giving the end */
|
||||
/* point of each contour within the outline. For */
|
||||
/* example, the first contour is defined by the points */
|
||||
/* `0' to `contours[0]', the second one is defined by */
|
||||
/* the points `contours[0]+1' to `contours[1]', etc. */
|
||||
/* */
|
||||
/* flags :: A set of bit flags used to characterize the outline */
|
||||
/* and give hints to the scan-converter and hinter on */
|
||||
/* how to convert/grid-fit it. See @PVG_FT_OUTLINE_FLAGS.*/
|
||||
/* */
|
||||
typedef struct PVG_FT_Outline_
|
||||
{
|
||||
int n_contours; /* number of contours in glyph */
|
||||
int n_points; /* number of points in the glyph */
|
||||
|
||||
PVG_FT_Vector* points; /* the outline's points */
|
||||
char* tags; /* the points flags */
|
||||
int* contours; /* the contour end points */
|
||||
char* contours_flag; /* the contour open flags */
|
||||
|
||||
int flags; /* outline masks */
|
||||
|
||||
} PVG_FT_Outline;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Enum> */
|
||||
/* PVG_FT_OUTLINE_FLAGS */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A list of bit-field constants use for the flags in an outline's */
|
||||
/* `flags' field. */
|
||||
/* */
|
||||
/* <Values> */
|
||||
/* PVG_FT_OUTLINE_NONE :: */
|
||||
/* Value~0 is reserved. */
|
||||
/* */
|
||||
/* PVG_FT_OUTLINE_OWNER :: */
|
||||
/* If set, this flag indicates that the outline's field arrays */
|
||||
/* (i.e., `points', `flags', and `contours') are `owned' by the */
|
||||
/* outline object, and should thus be freed when it is destroyed. */
|
||||
/* */
|
||||
/* PVG_FT_OUTLINE_EVEN_ODD_FILL :: */
|
||||
/* By default, outlines are filled using the non-zero winding rule. */
|
||||
/* If set to 1, the outline will be filled using the even-odd fill */
|
||||
/* rule (only works with the smooth rasterizer). */
|
||||
/* */
|
||||
/* PVG_FT_OUTLINE_REVERSE_FILL :: */
|
||||
/* By default, outside contours of an outline are oriented in */
|
||||
/* clock-wise direction, as defined in the TrueType specification. */
|
||||
/* This flag is set if the outline uses the opposite direction */
|
||||
/* (typically for Type~1 fonts). This flag is ignored by the scan */
|
||||
/* converter. */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* There exists a second mechanism to pass the drop-out mode to the */
|
||||
/* B/W rasterizer; see the `tags' field in @PVG_FT_Outline. */
|
||||
/* */
|
||||
/* Please refer to the description of the `SCANTYPE' instruction in */
|
||||
/* the OpenType specification (in file `ttinst1.doc') how simple */
|
||||
/* drop-outs, smart drop-outs, and stubs are defined. */
|
||||
/* */
|
||||
#define PVG_FT_OUTLINE_NONE 0x0
|
||||
#define PVG_FT_OUTLINE_OWNER 0x1
|
||||
#define PVG_FT_OUTLINE_EVEN_ODD_FILL 0x2
|
||||
#define PVG_FT_OUTLINE_REVERSE_FILL 0x4
|
||||
|
||||
/* */
|
||||
|
||||
#define PVG_FT_CURVE_TAG( flag ) ( flag & 3 )
|
||||
|
||||
#define PVG_FT_CURVE_TAG_ON 1
|
||||
#define PVG_FT_CURVE_TAG_CONIC 0
|
||||
#define PVG_FT_CURVE_TAG_CUBIC 2
|
||||
|
||||
|
||||
#define PVG_FT_Curve_Tag_On PVG_FT_CURVE_TAG_ON
|
||||
#define PVG_FT_Curve_Tag_Conic PVG_FT_CURVE_TAG_CONIC
|
||||
#define PVG_FT_Curve_Tag_Cubic PVG_FT_CURVE_TAG_CUBIC
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* PVG_FT_Outline_Check */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* Check the contents of an outline descriptor. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* outline :: A handle to a source outline. */
|
||||
/* */
|
||||
/* <Return> */
|
||||
/* FreeType error code. 0~means success. */
|
||||
/* */
|
||||
PVG_FT_Error
|
||||
PVG_FT_Outline_Check( PVG_FT_Outline* outline );
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* PVG_FT_Outline_Get_CBox */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* Return an outline's `control box'. The control box encloses all */
|
||||
/* the outline's points, including Bézier control points. Though it */
|
||||
/* coincides with the exact bounding box for most glyphs, it can be */
|
||||
/* slightly larger in some situations (like when rotating an outline */
|
||||
/* that contains Bézier outside arcs). */
|
||||
/* */
|
||||
/* Computing the control box is very fast, while getting the bounding */
|
||||
/* box can take much more time as it needs to walk over all segments */
|
||||
/* and arcs in the outline. To get the latter, you can use the */
|
||||
/* `ftbbox' component, which is dedicated to this single task. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* outline :: A pointer to the source outline descriptor. */
|
||||
/* */
|
||||
/* <Output> */
|
||||
/* acbox :: The outline's control box. */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* See @PVG_FT_Glyph_Get_CBox for a discussion of tricky fonts. */
|
||||
/* */
|
||||
void
|
||||
PVG_FT_Outline_Get_CBox( const PVG_FT_Outline* outline,
|
||||
PVG_FT_BBox *acbox );
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* PVG_FT_Span */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A structure used to model a single span of gray (or black) pixels */
|
||||
/* when rendering a monochrome or anti-aliased bitmap. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* x :: The span's horizontal start position. */
|
||||
/* */
|
||||
/* len :: The span's length in pixels. */
|
||||
/* */
|
||||
/* coverage :: The span color/coverage, ranging from 0 (background) */
|
||||
/* to 255 (foreground). Only used for anti-aliased */
|
||||
/* rendering. */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* This structure is used by the span drawing callback type named */
|
||||
/* @PVG_FT_SpanFunc that takes the y~coordinate of the span as a */
|
||||
/* parameter. */
|
||||
/* */
|
||||
/* The coverage value is always between 0 and 255. If you want less */
|
||||
/* gray values, the callback function has to reduce them. */
|
||||
/* */
|
||||
typedef struct PVG_FT_Span_
|
||||
{
|
||||
int x;
|
||||
int len;
|
||||
int y;
|
||||
unsigned char coverage;
|
||||
|
||||
} PVG_FT_Span;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <FuncType> */
|
||||
/* PVG_FT_SpanFunc */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A function used as a call-back by the anti-aliased renderer in */
|
||||
/* order to let client applications draw themselves the gray pixel */
|
||||
/* spans on each scan line. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* y :: The scanline's y~coordinate. */
|
||||
/* */
|
||||
/* count :: The number of spans to draw on this scanline. */
|
||||
/* */
|
||||
/* spans :: A table of `count' spans to draw on the scanline. */
|
||||
/* */
|
||||
/* user :: User-supplied data that is passed to the callback. */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* This callback allows client applications to directly render the */
|
||||
/* gray spans of the anti-aliased bitmap to any kind of surfaces. */
|
||||
/* */
|
||||
/* This can be used to write anti-aliased outlines directly to a */
|
||||
/* given background bitmap, and even perform translucency. */
|
||||
/* */
|
||||
/* Note that the `count' field cannot be greater than a fixed value */
|
||||
/* defined by the `PVG_FT_MAX_GRAY_SPANS' configuration macro in */
|
||||
/* `ftoption.h'. By default, this value is set to~32, which means */
|
||||
/* that if there are more than 32~spans on a given scanline, the */
|
||||
/* callback is called several times with the same `y' parameter in */
|
||||
/* order to draw all callbacks. */
|
||||
/* */
|
||||
/* Otherwise, the callback is only called once per scan-line, and */
|
||||
/* only for those scanlines that do have `gray' pixels on them. */
|
||||
/* */
|
||||
typedef void
|
||||
(*PVG_FT_SpanFunc)( int count,
|
||||
const PVG_FT_Span* spans,
|
||||
void* user );
|
||||
|
||||
#define PVG_FT_Raster_Span_Func PVG_FT_SpanFunc
|
||||
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Enum> */
|
||||
/* PVG_FT_RASTER_FLAG_XXX */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A list of bit flag constants as used in the `flags' field of a */
|
||||
/* @PVG_FT_Raster_Params structure. */
|
||||
/* */
|
||||
/* <Values> */
|
||||
/* PVG_FT_RASTER_FLAG_DEFAULT :: This value is 0. */
|
||||
/* */
|
||||
/* PVG_FT_RASTER_FLAG_AA :: This flag is set to indicate that an */
|
||||
/* anti-aliased glyph image should be */
|
||||
/* generated. Otherwise, it will be */
|
||||
/* monochrome (1-bit). */
|
||||
/* */
|
||||
/* PVG_FT_RASTER_FLAG_DIRECT :: This flag is set to indicate direct */
|
||||
/* rendering. In this mode, client */
|
||||
/* applications must provide their own span */
|
||||
/* callback. This lets them directly */
|
||||
/* draw or compose over an existing bitmap. */
|
||||
/* If this bit is not set, the target */
|
||||
/* pixmap's buffer _must_ be zeroed before */
|
||||
/* rendering. */
|
||||
/* */
|
||||
/* Note that for now, direct rendering is */
|
||||
/* only possible with anti-aliased glyphs. */
|
||||
/* */
|
||||
/* PVG_FT_RASTER_FLAG_CLIP :: This flag is only used in direct */
|
||||
/* rendering mode. If set, the output will */
|
||||
/* be clipped to a box specified in the */
|
||||
/* `clip_box' field of the */
|
||||
/* @PVG_FT_Raster_Params structure. */
|
||||
/* */
|
||||
/* Note that by default, the glyph bitmap */
|
||||
/* is clipped to the target pixmap, except */
|
||||
/* in direct rendering mode where all spans */
|
||||
/* are generated if no clipping box is set. */
|
||||
/* */
|
||||
#define PVG_FT_RASTER_FLAG_DEFAULT 0x0
|
||||
#define PVG_FT_RASTER_FLAG_AA 0x1
|
||||
#define PVG_FT_RASTER_FLAG_DIRECT 0x2
|
||||
#define PVG_FT_RASTER_FLAG_CLIP 0x4
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* PVG_FT_Raster_Params */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A structure to hold the arguments used by a raster's render */
|
||||
/* function. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* target :: The target bitmap. */
|
||||
/* */
|
||||
/* source :: A pointer to the source glyph image (e.g., an */
|
||||
/* @PVG_FT_Outline). */
|
||||
/* */
|
||||
/* flags :: The rendering flags. */
|
||||
/* */
|
||||
/* gray_spans :: The gray span drawing callback. */
|
||||
/* */
|
||||
/* black_spans :: The black span drawing callback. UNIMPLEMENTED! */
|
||||
/* */
|
||||
/* bit_test :: The bit test callback. UNIMPLEMENTED! */
|
||||
/* */
|
||||
/* bit_set :: The bit set callback. UNIMPLEMENTED! */
|
||||
/* */
|
||||
/* user :: User-supplied data that is passed to each drawing */
|
||||
/* callback. */
|
||||
/* */
|
||||
/* clip_box :: An optional clipping box. It is only used in */
|
||||
/* direct rendering mode. Note that coordinates here */
|
||||
/* should be expressed in _integer_ pixels (and not in */
|
||||
/* 26.6 fixed-point units). */
|
||||
/* */
|
||||
/* <Note> */
|
||||
/* An anti-aliased glyph bitmap is drawn if the @PVG_FT_RASTER_FLAG_AA */
|
||||
/* bit flag is set in the `flags' field, otherwise a monochrome */
|
||||
/* bitmap is generated. */
|
||||
/* */
|
||||
/* If the @PVG_FT_RASTER_FLAG_DIRECT bit flag is set in `flags', the */
|
||||
/* raster will call the `gray_spans' callback to draw gray pixel */
|
||||
/* spans, in the case of an aa glyph bitmap, it will call */
|
||||
/* `black_spans', and `bit_test' and `bit_set' in the case of a */
|
||||
/* monochrome bitmap. This allows direct composition over a */
|
||||
/* pre-existing bitmap through user-provided callbacks to perform the */
|
||||
/* span drawing/composition. */
|
||||
/* */
|
||||
/* Note that the `bit_test' and `bit_set' callbacks are required when */
|
||||
/* rendering a monochrome bitmap, as they are crucial to implement */
|
||||
/* correct drop-out control as defined in the TrueType specification. */
|
||||
/* */
|
||||
typedef struct PVG_FT_Raster_Params_
|
||||
{
|
||||
const void* source;
|
||||
int flags;
|
||||
PVG_FT_SpanFunc gray_spans;
|
||||
void* user;
|
||||
PVG_FT_BBox clip_box;
|
||||
|
||||
} PVG_FT_Raster_Params;
|
||||
|
||||
|
||||
void
|
||||
PVG_FT_Raster_Render(const PVG_FT_Raster_Params *params);
|
||||
|
||||
#endif // PLUTOVG_FT_RASTER_H
|
||||
1873
3rdparty/plutosvg/plutovg/source/plutovg-ft-stroker.c
vendored
Normal file
1873
3rdparty/plutosvg/plutovg/source/plutovg-ft-stroker.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
320
3rdparty/plutosvg/plutovg/source/plutovg-ft-stroker.h
vendored
Normal file
320
3rdparty/plutosvg/plutovg/source/plutovg-ft-stroker.h
vendored
Normal file
@@ -0,0 +1,320 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* ftstroke.h */
|
||||
/* */
|
||||
/* FreeType path stroker (specification). */
|
||||
/* */
|
||||
/* Copyright 2002-2006, 2008, 2009, 2011-2012 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* license, FTL.TXT. By continuing to use, modify, or distribute */
|
||||
/* this file you indicate that you have read the license and */
|
||||
/* understand and accept it fully. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
#ifndef PLUTOVG_FT_STROKER_H
|
||||
#define PLUTOVG_FT_STROKER_H
|
||||
|
||||
#include "plutovg-ft-raster.h"
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @type:
|
||||
* PVG_FT_Stroker
|
||||
*
|
||||
* @description:
|
||||
* Opaque handler to a path stroker object.
|
||||
*/
|
||||
typedef struct PVG_FT_StrokerRec_* PVG_FT_Stroker;
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @enum:
|
||||
* PVG_FT_Stroker_LineJoin
|
||||
*
|
||||
* @description:
|
||||
* These values determine how two joining lines are rendered
|
||||
* in a stroker.
|
||||
*
|
||||
* @values:
|
||||
* PVG_FT_STROKER_LINEJOIN_ROUND ::
|
||||
* Used to render rounded line joins. Circular arcs are used
|
||||
* to join two lines smoothly.
|
||||
*
|
||||
* PVG_FT_STROKER_LINEJOIN_BEVEL ::
|
||||
* Used to render beveled line joins. The outer corner of
|
||||
* the joined lines is filled by enclosing the triangular
|
||||
* region of the corner with a straight line between the
|
||||
* outer corners of each stroke.
|
||||
*
|
||||
* PVG_FT_STROKER_LINEJOIN_MITER_FIXED ::
|
||||
* Used to render mitered line joins, with fixed bevels if the
|
||||
* miter limit is exceeded. The outer edges of the strokes
|
||||
* for the two segments are extended until they meet at an
|
||||
* angle. If the segments meet at too sharp an angle (such
|
||||
* that the miter would extend from the intersection of the
|
||||
* segments a distance greater than the product of the miter
|
||||
* limit value and the border radius), then a bevel join (see
|
||||
* above) is used instead. This prevents long spikes being
|
||||
* created. PVG_FT_STROKER_LINEJOIN_MITER_FIXED generates a miter
|
||||
* line join as used in PostScript and PDF.
|
||||
*
|
||||
* PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE ::
|
||||
* PVG_FT_STROKER_LINEJOIN_MITER ::
|
||||
* Used to render mitered line joins, with variable bevels if
|
||||
* the miter limit is exceeded. The intersection of the
|
||||
* strokes is clipped at a line perpendicular to the bisector
|
||||
* of the angle between the strokes, at the distance from the
|
||||
* intersection of the segments equal to the product of the
|
||||
* miter limit value and the border radius. This prevents
|
||||
* long spikes being created.
|
||||
* PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE generates a mitered line
|
||||
* join as used in XPS. PVG_FT_STROKER_LINEJOIN_MITER is an alias
|
||||
* for PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE, retained for
|
||||
* backwards compatibility.
|
||||
*/
|
||||
typedef enum PVG_FT_Stroker_LineJoin_
|
||||
{
|
||||
PVG_FT_STROKER_LINEJOIN_ROUND = 0,
|
||||
PVG_FT_STROKER_LINEJOIN_BEVEL = 1,
|
||||
PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE = 2,
|
||||
PVG_FT_STROKER_LINEJOIN_MITER = PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE,
|
||||
PVG_FT_STROKER_LINEJOIN_MITER_FIXED = 3
|
||||
|
||||
} PVG_FT_Stroker_LineJoin;
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @enum:
|
||||
* PVG_FT_Stroker_LineCap
|
||||
*
|
||||
* @description:
|
||||
* These values determine how the end of opened sub-paths are
|
||||
* rendered in a stroke.
|
||||
*
|
||||
* @values:
|
||||
* PVG_FT_STROKER_LINECAP_BUTT ::
|
||||
* The end of lines is rendered as a full stop on the last
|
||||
* point itself.
|
||||
*
|
||||
* PVG_FT_STROKER_LINECAP_ROUND ::
|
||||
* The end of lines is rendered as a half-circle around the
|
||||
* last point.
|
||||
*
|
||||
* PVG_FT_STROKER_LINECAP_SQUARE ::
|
||||
* The end of lines is rendered as a square around the
|
||||
* last point.
|
||||
*/
|
||||
typedef enum PVG_FT_Stroker_LineCap_
|
||||
{
|
||||
PVG_FT_STROKER_LINECAP_BUTT = 0,
|
||||
PVG_FT_STROKER_LINECAP_ROUND,
|
||||
PVG_FT_STROKER_LINECAP_SQUARE
|
||||
|
||||
} PVG_FT_Stroker_LineCap;
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @enum:
|
||||
* PVG_FT_StrokerBorder
|
||||
*
|
||||
* @description:
|
||||
* These values are used to select a given stroke border
|
||||
* in @PVG_FT_Stroker_GetBorderCounts and @PVG_FT_Stroker_ExportBorder.
|
||||
*
|
||||
* @values:
|
||||
* PVG_FT_STROKER_BORDER_LEFT ::
|
||||
* Select the left border, relative to the drawing direction.
|
||||
*
|
||||
* PVG_FT_STROKER_BORDER_RIGHT ::
|
||||
* Select the right border, relative to the drawing direction.
|
||||
*
|
||||
* @note:
|
||||
* Applications are generally interested in the `inside' and `outside'
|
||||
* borders. However, there is no direct mapping between these and the
|
||||
* `left' and `right' ones, since this really depends on the glyph's
|
||||
* drawing orientation, which varies between font formats.
|
||||
*
|
||||
* You can however use @PVG_FT_Outline_GetInsideBorder and
|
||||
* @PVG_FT_Outline_GetOutsideBorder to get these.
|
||||
*/
|
||||
typedef enum PVG_FT_StrokerBorder_
|
||||
{
|
||||
PVG_FT_STROKER_BORDER_LEFT = 0,
|
||||
PVG_FT_STROKER_BORDER_RIGHT
|
||||
|
||||
} PVG_FT_StrokerBorder;
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Stroker_New
|
||||
*
|
||||
* @description:
|
||||
* Create a new stroker object.
|
||||
*
|
||||
* @input:
|
||||
* library ::
|
||||
* FreeType library handle.
|
||||
*
|
||||
* @output:
|
||||
* astroker ::
|
||||
* A new stroker object handle. NULL in case of error.
|
||||
*
|
||||
* @return:
|
||||
* FreeType error code. 0~means success.
|
||||
*/
|
||||
PVG_FT_Error
|
||||
PVG_FT_Stroker_New( PVG_FT_Stroker *astroker );
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Stroker_Set
|
||||
*
|
||||
* @description:
|
||||
* Reset a stroker object's attributes.
|
||||
*
|
||||
* @input:
|
||||
* stroker ::
|
||||
* The target stroker handle.
|
||||
*
|
||||
* radius ::
|
||||
* The border radius.
|
||||
*
|
||||
* line_cap ::
|
||||
* The line cap style.
|
||||
*
|
||||
* line_join ::
|
||||
* The line join style.
|
||||
*
|
||||
* miter_limit ::
|
||||
* The miter limit for the PVG_FT_STROKER_LINEJOIN_MITER_FIXED and
|
||||
* PVG_FT_STROKER_LINEJOIN_MITER_VARIABLE line join styles,
|
||||
* expressed as 16.16 fixed-point value.
|
||||
*
|
||||
* @note:
|
||||
* The radius is expressed in the same units as the outline
|
||||
* coordinates.
|
||||
*/
|
||||
void
|
||||
PVG_FT_Stroker_Set( PVG_FT_Stroker stroker,
|
||||
PVG_FT_Fixed radius,
|
||||
PVG_FT_Stroker_LineCap line_cap,
|
||||
PVG_FT_Stroker_LineJoin line_join,
|
||||
PVG_FT_Fixed miter_limit );
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Stroker_ParseOutline
|
||||
*
|
||||
* @description:
|
||||
* A convenience function used to parse a whole outline with
|
||||
* the stroker. The resulting outline(s) can be retrieved
|
||||
* later by functions like @PVG_FT_Stroker_GetCounts and @PVG_FT_Stroker_Export.
|
||||
*
|
||||
* @input:
|
||||
* stroker ::
|
||||
* The target stroker handle.
|
||||
*
|
||||
* outline ::
|
||||
* The source outline.
|
||||
*
|
||||
*
|
||||
* @return:
|
||||
* FreeType error code. 0~means success.
|
||||
*
|
||||
* @note:
|
||||
* If `opened' is~0 (the default), the outline is treated as a closed
|
||||
* path, and the stroker generates two distinct `border' outlines.
|
||||
*
|
||||
*
|
||||
* This function calls @PVG_FT_Stroker_Rewind automatically.
|
||||
*/
|
||||
PVG_FT_Error
|
||||
PVG_FT_Stroker_ParseOutline( PVG_FT_Stroker stroker,
|
||||
const PVG_FT_Outline* outline);
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Stroker_GetCounts
|
||||
*
|
||||
* @description:
|
||||
* Call this function once you have finished parsing your paths
|
||||
* with the stroker. It returns the number of points and
|
||||
* contours necessary to export all points/borders from the stroked
|
||||
* outline/path.
|
||||
*
|
||||
* @input:
|
||||
* stroker ::
|
||||
* The target stroker handle.
|
||||
*
|
||||
* @output:
|
||||
* anum_points ::
|
||||
* The number of points.
|
||||
*
|
||||
* anum_contours ::
|
||||
* The number of contours.
|
||||
*
|
||||
* @return:
|
||||
* FreeType error code. 0~means success.
|
||||
*/
|
||||
PVG_FT_Error
|
||||
PVG_FT_Stroker_GetCounts( PVG_FT_Stroker stroker,
|
||||
PVG_FT_UInt *anum_points,
|
||||
PVG_FT_UInt *anum_contours );
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Stroker_Export
|
||||
*
|
||||
* @description:
|
||||
* Call this function after @PVG_FT_Stroker_GetBorderCounts to
|
||||
* export all borders to your own @PVG_FT_Outline structure.
|
||||
*
|
||||
* Note that this function appends the border points and
|
||||
* contours to your outline, but does not try to resize its
|
||||
* arrays.
|
||||
*
|
||||
* @input:
|
||||
* stroker ::
|
||||
* The target stroker handle.
|
||||
*
|
||||
* outline ::
|
||||
* The target outline handle.
|
||||
*/
|
||||
void
|
||||
PVG_FT_Stroker_Export( PVG_FT_Stroker stroker,
|
||||
PVG_FT_Outline* outline );
|
||||
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* @function:
|
||||
* PVG_FT_Stroker_Done
|
||||
*
|
||||
* @description:
|
||||
* Destroy a stroker object.
|
||||
*
|
||||
* @input:
|
||||
* stroker ::
|
||||
* A stroker handle. Can be NULL.
|
||||
*/
|
||||
void
|
||||
PVG_FT_Stroker_Done( PVG_FT_Stroker stroker );
|
||||
|
||||
|
||||
#endif // PLUTOVG_FT_STROKER_H
|
||||
173
3rdparty/plutosvg/plutovg/source/plutovg-ft-types.h
vendored
Normal file
173
3rdparty/plutosvg/plutovg/source/plutovg-ft-types.h
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* fttypes.h
|
||||
*
|
||||
* FreeType simple types definitions (specification only).
|
||||
*
|
||||
* Copyright (C) 1996-2020 by
|
||||
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
*
|
||||
* This file is part of the FreeType project, and may only be used,
|
||||
* modified, and distributed under the terms of the FreeType project
|
||||
* license, FTL.TXT. By continuing to use, modify, or distribute
|
||||
* this file you indicate that you have read the license and
|
||||
* understand and accept it fully.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PLUTOVG_FT_TYPES_H
|
||||
#define PLUTOVG_FT_TYPES_H
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Fixed */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* This type is used to store 16.16 fixed-point values, like scaling */
|
||||
/* values or matrix coefficients. */
|
||||
/* */
|
||||
typedef signed long PVG_FT_Fixed;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Int */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A typedef for the int type. */
|
||||
/* */
|
||||
typedef signed int PVG_FT_Int;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_UInt */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A typedef for the unsigned int type. */
|
||||
/* */
|
||||
typedef unsigned int PVG_FT_UInt;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Long */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A typedef for signed long. */
|
||||
/* */
|
||||
typedef signed long PVG_FT_Long;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_ULong */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A typedef for unsigned long. */
|
||||
/* */
|
||||
typedef unsigned long PVG_FT_ULong;
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Short */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A typedef for signed short. */
|
||||
/* */
|
||||
typedef signed short PVG_FT_Short;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Byte */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A simple typedef for the _unsigned_ char type. */
|
||||
/* */
|
||||
typedef unsigned char PVG_FT_Byte;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Bool */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A typedef of unsigned char, used for simple booleans. As usual, */
|
||||
/* values 1 and~0 represent true and false, respectively. */
|
||||
/* */
|
||||
typedef unsigned char PVG_FT_Bool;
|
||||
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Error */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* The FreeType error code type. A value of~0 is always interpreted */
|
||||
/* as a successful operation. */
|
||||
/* */
|
||||
typedef int PVG_FT_Error;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Type> */
|
||||
/* PVG_FT_Pos */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* The type PVG_FT_Pos is used to store vectorial coordinates. Depending */
|
||||
/* on the context, these can represent distances in integer font */
|
||||
/* units, or 16.16, or 26.6 fixed-point pixel coordinates. */
|
||||
/* */
|
||||
typedef signed long PVG_FT_Pos;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* PVG_FT_Vector */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* A simple structure used to store a 2D vector; coordinates are of */
|
||||
/* the PVG_FT_Pos type. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* x :: The horizontal coordinate. */
|
||||
/* y :: The vertical coordinate. */
|
||||
/* */
|
||||
typedef struct PVG_FT_Vector_
|
||||
{
|
||||
PVG_FT_Pos x;
|
||||
PVG_FT_Pos y;
|
||||
|
||||
} PVG_FT_Vector;
|
||||
|
||||
|
||||
typedef long long int PVG_FT_Int64;
|
||||
typedef unsigned long long int PVG_FT_UInt64;
|
||||
|
||||
typedef signed int PVG_FT_Int32;
|
||||
typedef unsigned int PVG_FT_UInt32;
|
||||
|
||||
#define PVG_FT_BOOL( x ) ( (PVG_FT_Bool)( x ) )
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#endif // PLUTOVG_FT_TYPES_H
|
||||
231
3rdparty/plutosvg/plutovg/source/plutovg-matrix.c
vendored
Normal file
231
3rdparty/plutosvg/plutovg/source/plutovg-matrix.c
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
#include "plutovg.h"
|
||||
#include "plutovg-utils.h"
|
||||
|
||||
void plutovg_matrix_init(plutovg_matrix_t* matrix, float a, float b, float c, float d, float e, float f)
|
||||
{
|
||||
matrix->a = a; matrix->b = b;
|
||||
matrix->c = c; matrix->d = d;
|
||||
matrix->e = e; matrix->f = f;
|
||||
}
|
||||
|
||||
void plutovg_matrix_init_identity(plutovg_matrix_t* matrix)
|
||||
{
|
||||
matrix->a = 1; matrix->b = 0;
|
||||
matrix->c = 0; matrix->d = 1;
|
||||
matrix->e = 0; matrix->f = 0;
|
||||
}
|
||||
|
||||
void plutovg_matrix_init_translate(plutovg_matrix_t* matrix, float tx, float ty)
|
||||
{
|
||||
plutovg_matrix_init(matrix, 1, 0, 0, 1, tx, ty);
|
||||
}
|
||||
|
||||
void plutovg_matrix_init_scale(plutovg_matrix_t* matrix, float sx, float sy)
|
||||
{
|
||||
plutovg_matrix_init(matrix, sx, 0, 0, sy, 0, 0);
|
||||
}
|
||||
|
||||
void plutovg_matrix_init_rotate(plutovg_matrix_t* matrix, float angle)
|
||||
{
|
||||
float c = cosf(angle);
|
||||
float s = sinf(angle);
|
||||
plutovg_matrix_init(matrix, c, s, -s, c, 0, 0);
|
||||
}
|
||||
|
||||
void plutovg_matrix_init_shear(plutovg_matrix_t* matrix, float shx, float shy)
|
||||
{
|
||||
plutovg_matrix_init(matrix, 1, tanf(shy), tanf(shx), 1, 0, 0);
|
||||
}
|
||||
|
||||
void plutovg_matrix_translate(plutovg_matrix_t* matrix, float tx, float ty)
|
||||
{
|
||||
plutovg_matrix_t m;
|
||||
plutovg_matrix_init_translate(&m, tx, ty);
|
||||
plutovg_matrix_multiply(matrix, &m, matrix);
|
||||
}
|
||||
|
||||
void plutovg_matrix_scale(plutovg_matrix_t* matrix, float sx, float sy)
|
||||
{
|
||||
plutovg_matrix_t m;
|
||||
plutovg_matrix_init_scale(&m, sx, sy);
|
||||
plutovg_matrix_multiply(matrix, &m, matrix);
|
||||
}
|
||||
|
||||
void plutovg_matrix_rotate(plutovg_matrix_t* matrix, float angle)
|
||||
{
|
||||
plutovg_matrix_t m;
|
||||
plutovg_matrix_init_rotate(&m, angle);
|
||||
plutovg_matrix_multiply(matrix, &m, matrix);
|
||||
}
|
||||
|
||||
void plutovg_matrix_shear(plutovg_matrix_t* matrix, float shx, float shy)
|
||||
{
|
||||
plutovg_matrix_t m;
|
||||
plutovg_matrix_init_shear(&m, shx, shy);
|
||||
plutovg_matrix_multiply(matrix, &m, matrix);
|
||||
}
|
||||
|
||||
void plutovg_matrix_multiply(plutovg_matrix_t* matrix, const plutovg_matrix_t* left, const plutovg_matrix_t* right)
|
||||
{
|
||||
float a = left->a * right->a + left->b * right->c;
|
||||
float b = left->a * right->b + left->b * right->d;
|
||||
float c = left->c * right->a + left->d * right->c;
|
||||
float d = left->c * right->b + left->d * right->d;
|
||||
float e = left->e * right->a + left->f * right->c + right->e;
|
||||
float f = left->e * right->b + left->f * right->d + right->f;
|
||||
plutovg_matrix_init(matrix, a, b, c, d, e, f);
|
||||
}
|
||||
|
||||
bool plutovg_matrix_invert(const plutovg_matrix_t* matrix, plutovg_matrix_t* inverse)
|
||||
{
|
||||
float det = (matrix->a * matrix->d - matrix->b * matrix->c);
|
||||
if(det == 0.f)
|
||||
return false;
|
||||
if(inverse) {
|
||||
float inv_det = 1.f / det;
|
||||
float a = matrix->a * inv_det;
|
||||
float b = matrix->b * inv_det;
|
||||
float c = matrix->c * inv_det;
|
||||
float d = matrix->d * inv_det;
|
||||
float e = (matrix->c * matrix->f - matrix->d * matrix->e) * inv_det;
|
||||
float f = (matrix->b * matrix->e - matrix->a * matrix->f) * inv_det;
|
||||
plutovg_matrix_init(inverse, d, -b, -c, a, e, f);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void plutovg_matrix_map(const plutovg_matrix_t* matrix, float x, float y, float* xx, float* yy)
|
||||
{
|
||||
*xx = x * matrix->a + y * matrix->c + matrix->e;
|
||||
*yy = x * matrix->b + y * matrix->d + matrix->f;
|
||||
}
|
||||
|
||||
void plutovg_matrix_map_point(const plutovg_matrix_t* matrix, const plutovg_point_t* src, plutovg_point_t* dst)
|
||||
{
|
||||
plutovg_matrix_map(matrix, src->x, src->y, &dst->x, &dst->y);
|
||||
}
|
||||
|
||||
void plutovg_matrix_map_points(const plutovg_matrix_t* matrix, const plutovg_point_t* src, plutovg_point_t* dst, int count)
|
||||
{
|
||||
for(int i = 0; i < count; ++i) {
|
||||
plutovg_matrix_map_point(matrix, &src[i], &dst[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void plutovg_matrix_map_rect(const plutovg_matrix_t* matrix, const plutovg_rect_t* src, plutovg_rect_t* dst)
|
||||
{
|
||||
plutovg_point_t p[4];
|
||||
p[0].x = src->x;
|
||||
p[0].y = src->y;
|
||||
p[1].x = src->x + src->w;
|
||||
p[1].y = src->y;
|
||||
p[2].x = src->x + src->w;
|
||||
p[2].y = src->y + src->h;
|
||||
p[3].x = src->x;
|
||||
p[3].y = src->y + src->h;
|
||||
plutovg_matrix_map_points(matrix, p, p, 4);
|
||||
|
||||
float l = p[0].x;
|
||||
float t = p[0].y;
|
||||
float r = p[0].x;
|
||||
float b = p[0].y;
|
||||
|
||||
for(int i = 1; i < 4; i++) {
|
||||
if(p[i].x < l) l = p[i].x;
|
||||
if(p[i].x > r) r = p[i].x;
|
||||
if(p[i].y < t) t = p[i].y;
|
||||
if(p[i].y > b) b = p[i].y;
|
||||
}
|
||||
|
||||
dst->x = l;
|
||||
dst->y = t;
|
||||
dst->w = r - l;
|
||||
dst->h = b - t;
|
||||
}
|
||||
|
||||
static int parse_matrix_parameters(const char** begin, const char* end, float values[6], int required, int optional)
|
||||
{
|
||||
if(!plutovg_skip_ws_and_delim(begin, end, '('))
|
||||
return 0;
|
||||
int count = 0;
|
||||
int max_count = required + optional;
|
||||
bool has_trailing_comma = false;
|
||||
for(; count < max_count; ++count) {
|
||||
if(!plutovg_parse_number(begin, end, values + count))
|
||||
break;
|
||||
plutovg_skip_ws_or_comma(begin, end, &has_trailing_comma);
|
||||
}
|
||||
|
||||
if(!has_trailing_comma && (count == required || count == max_count)
|
||||
&& plutovg_skip_delim(begin, end, ')')) {
|
||||
return count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool plutovg_matrix_parse(plutovg_matrix_t* matrix, const char* data, int length)
|
||||
{
|
||||
float values[6];
|
||||
plutovg_matrix_init_identity(matrix);
|
||||
if(length == -1)
|
||||
length = strlen(data);
|
||||
const char* it = data;
|
||||
const char* end = it + length;
|
||||
bool has_trailing_comma = false;
|
||||
plutovg_skip_ws(&it, end);
|
||||
while(it < end) {
|
||||
if(plutovg_skip_string(&it, end, "matrix")) {
|
||||
int count = parse_matrix_parameters(&it, end, values, 6, 0);
|
||||
if(count == 0)
|
||||
return false;
|
||||
plutovg_matrix_t m = { values[0], values[1], values[2], values[3], values[4], values[5] };
|
||||
plutovg_matrix_multiply(matrix, &m, matrix);
|
||||
} else if(plutovg_skip_string(&it, end, "translate")) {
|
||||
int count = parse_matrix_parameters(&it, end, values, 1, 1);
|
||||
if(count == 0)
|
||||
return false;
|
||||
if(count == 1) {
|
||||
plutovg_matrix_translate(matrix, values[0], 0);
|
||||
} else {
|
||||
plutovg_matrix_translate(matrix, values[0], values[1]);
|
||||
}
|
||||
} else if(plutovg_skip_string(&it, end, "scale")) {
|
||||
int count = parse_matrix_parameters(&it, end, values, 1, 1);
|
||||
if(count == 0)
|
||||
return false;
|
||||
if(count == 1) {
|
||||
plutovg_matrix_scale(matrix, values[0], values[0]);
|
||||
} else {
|
||||
plutovg_matrix_scale(matrix, values[0], values[1]);
|
||||
}
|
||||
} else if(plutovg_skip_string(&it, end, "rotate")) {
|
||||
int count = parse_matrix_parameters(&it, end, values, 1, 2);
|
||||
if(count == 0)
|
||||
return false;
|
||||
if(count == 3)
|
||||
plutovg_matrix_translate(matrix, values[1], values[2]);
|
||||
plutovg_matrix_rotate(matrix, PLUTOVG_DEG2RAD(values[0]));
|
||||
if(count == 3) {
|
||||
plutovg_matrix_translate(matrix, -values[1], -values[2]);
|
||||
}
|
||||
} else if(plutovg_skip_string(&it, end, "skewX")) {
|
||||
int count = parse_matrix_parameters(&it, end, values, 1, 0);
|
||||
if(count == 0)
|
||||
return false;
|
||||
plutovg_matrix_shear(matrix, PLUTOVG_DEG2RAD(values[0]), 0);
|
||||
} else if(plutovg_skip_string(&it, end, "skewY")) {
|
||||
int count = parse_matrix_parameters(&it, end, values, 1, 0);
|
||||
if(count == 0)
|
||||
return false;
|
||||
plutovg_matrix_shear(matrix, 0, PLUTOVG_DEG2RAD(values[0]));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
plutovg_skip_ws_or_comma(&it, end, &has_trailing_comma);
|
||||
}
|
||||
|
||||
return !has_trailing_comma;
|
||||
}
|
||||
497
3rdparty/plutosvg/plutovg/source/plutovg-paint.c
vendored
Normal file
497
3rdparty/plutosvg/plutovg/source/plutovg-paint.c
vendored
Normal file
@@ -0,0 +1,497 @@
|
||||
#include "plutovg-private.h"
|
||||
#include "plutovg-utils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
void plutovg_color_init_rgb(plutovg_color_t* color, float r, float g, float b)
|
||||
{
|
||||
plutovg_color_init_rgba(color, r, g, b, 1.f);
|
||||
}
|
||||
|
||||
void plutovg_color_init_rgba(plutovg_color_t* color, float r, float g, float b, float a)
|
||||
{
|
||||
color->r = plutovg_clamp(r, 0.f, 1.f);
|
||||
color->g = plutovg_clamp(g, 0.f, 1.f);
|
||||
color->b = plutovg_clamp(b, 0.f, 1.f);
|
||||
color->a = plutovg_clamp(a, 0.f, 1.f);
|
||||
}
|
||||
|
||||
void plutovg_color_init_rgb8(plutovg_color_t* color, int r, int g, int b)
|
||||
{
|
||||
plutovg_color_init_rgba8(color, r, g, b, 255);
|
||||
}
|
||||
|
||||
void plutovg_color_init_rgba8(plutovg_color_t* color, int r, int g, int b, int a)
|
||||
{
|
||||
plutovg_color_init_rgba(color, r / 255.f, g / 255.f, b / 255.f, a / 255.f);
|
||||
}
|
||||
|
||||
void plutovg_color_init_rgba32(plutovg_color_t* color, unsigned int value)
|
||||
{
|
||||
uint8_t r = (value >> 24) & 0xFF;
|
||||
uint8_t g = (value >> 16) & 0xFF;
|
||||
uint8_t b = (value >> 8) & 0xFF;
|
||||
uint8_t a = (value >> 0) & 0xFF;
|
||||
plutovg_color_init_rgba8(color, r, g, b, a);
|
||||
}
|
||||
|
||||
void plutovg_color_init_argb32(plutovg_color_t* color, unsigned int value)
|
||||
{
|
||||
uint8_t a = (value >> 24) & 0xFF;
|
||||
uint8_t r = (value >> 16) & 0xFF;
|
||||
uint8_t g = (value >> 8) & 0xFF;
|
||||
uint8_t b = (value >> 0) & 0xFF;
|
||||
plutovg_color_init_rgba8(color, r, g, b, a);
|
||||
}
|
||||
|
||||
void plutovg_color_init_hsl(plutovg_color_t* color, float h, float s, float l)
|
||||
{
|
||||
plutovg_color_init_hsla(color, h, s, l, 1.f);
|
||||
}
|
||||
|
||||
static inline float hsl_component(float h, float s, float l, float n)
|
||||
{
|
||||
const float k = fmodf(n + h / 30.f, 12.f);
|
||||
const float a = s * plutovg_min(l, 1.f - l);
|
||||
return l - a * plutovg_max(-1.f, plutovg_min(1.f, plutovg_min(k - 3.f, 9.f - k)));
|
||||
}
|
||||
|
||||
void plutovg_color_init_hsla(plutovg_color_t* color, float h, float s, float l, float a)
|
||||
{
|
||||
h = fmodf(h, 360.f);
|
||||
if(h < 0.f) { h += 360.f; }
|
||||
|
||||
float r = hsl_component(h, s, l, 0);
|
||||
float g = hsl_component(h, s, l, 8);
|
||||
float b = hsl_component(h, s, l, 4);
|
||||
plutovg_color_init_rgba(color, r, g, b, a);
|
||||
}
|
||||
|
||||
unsigned int plutovg_color_to_rgba32(const plutovg_color_t* color)
|
||||
{
|
||||
uint32_t r = lroundf(color->r * 255);
|
||||
uint32_t g = lroundf(color->g * 255);
|
||||
uint32_t b = lroundf(color->b * 255);
|
||||
uint32_t a = lroundf(color->a * 255);
|
||||
return (r << 24) | (g << 16) | (b << 8) | (a);
|
||||
}
|
||||
|
||||
unsigned int plutovg_color_to_argb32(const plutovg_color_t* color)
|
||||
{
|
||||
uint32_t a = lroundf(color->a * 255);
|
||||
uint32_t r = lroundf(color->r * 255);
|
||||
uint32_t g = lroundf(color->g * 255);
|
||||
uint32_t b = lroundf(color->b * 255);
|
||||
return (a << 24) | (r << 16) | (g << 8) | (b);
|
||||
}
|
||||
|
||||
static inline uint8_t hex_digit(uint8_t c)
|
||||
{
|
||||
if(c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if(c >= 'a' && c <= 'f')
|
||||
return 10 + c - 'a';
|
||||
if(c >= 'A' && c <= 'F')
|
||||
return 10 + c - 'A';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint8_t hex_byte(uint8_t c1, uint8_t c2)
|
||||
{
|
||||
uint8_t h1 = hex_digit(c1);
|
||||
uint8_t h2 = hex_digit(c2);
|
||||
return (h1 << 4) | h2;
|
||||
}
|
||||
|
||||
#define MAX_NAME 20
|
||||
typedef struct {
|
||||
const char* name;
|
||||
uint32_t value;
|
||||
} color_entry_t;
|
||||
|
||||
static int color_entry_compare(const void* a, const void* b)
|
||||
{
|
||||
const char* name = a;
|
||||
const color_entry_t* entry = b;
|
||||
return strcmp(name, entry->name);
|
||||
}
|
||||
|
||||
static bool parse_rgb_component(const char** begin, const char* end, float* component)
|
||||
{
|
||||
float value = 0;
|
||||
if(!plutovg_parse_number(begin, end, &value))
|
||||
return false;
|
||||
if(plutovg_skip_delim(begin, end, '%'))
|
||||
value *= 2.55f;
|
||||
*component = plutovg_clamp(value, 0.f, 255.f) / 255.f;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_alpha_component(const char** begin, const char* end, float* component)
|
||||
{
|
||||
float value = 0;
|
||||
if(!plutovg_parse_number(begin, end, &value))
|
||||
return false;
|
||||
if(plutovg_skip_delim(begin, end, '%'))
|
||||
value /= 100.f;
|
||||
*component = plutovg_clamp(value, 0.f, 1.f);
|
||||
return true;
|
||||
}
|
||||
|
||||
int plutovg_color_parse(plutovg_color_t* color, const char* data, int length)
|
||||
{
|
||||
if(length == -1)
|
||||
length = strlen(data);
|
||||
const char* it = data;
|
||||
const char* end = it + length;
|
||||
plutovg_skip_ws(&it, end);
|
||||
if(plutovg_skip_delim(&it, end, '#')) {
|
||||
int r, g, b, a = 255;
|
||||
const char* begin = it;
|
||||
while(it < end && isxdigit(*it))
|
||||
++it;
|
||||
int count = it - begin;
|
||||
if(count == 3 || count == 4) {
|
||||
r = hex_byte(begin[0], begin[0]);
|
||||
g = hex_byte(begin[1], begin[1]);
|
||||
b = hex_byte(begin[2], begin[2]);
|
||||
if(count == 4) {
|
||||
a = hex_byte(begin[3], begin[3]);
|
||||
}
|
||||
} else if(count == 6 || count == 8) {
|
||||
r = hex_byte(begin[0], begin[1]);
|
||||
g = hex_byte(begin[2], begin[3]);
|
||||
b = hex_byte(begin[4], begin[5]);
|
||||
if(count == 8) {
|
||||
a = hex_byte(begin[6], begin[7]);
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
plutovg_color_init_rgba8(color, r, g, b, a);
|
||||
} else {
|
||||
int name_length = 0;
|
||||
char name[MAX_NAME + 1];
|
||||
while(it < end && name_length < MAX_NAME && isalpha(*it))
|
||||
name[name_length++] = tolower(*it++);
|
||||
name[name_length] = '\0';
|
||||
|
||||
if(strcmp(name, "transparent") == 0) {
|
||||
plutovg_color_init_rgba(color, 0, 0, 0, 0);
|
||||
} else if(strcmp(name, "rgb") == 0 || strcmp(name, "rgba") == 0) {
|
||||
if(!plutovg_skip_ws_and_delim(&it, end, '('))
|
||||
return 0;
|
||||
float r, g, b, a = 1.f;
|
||||
if(!parse_rgb_component(&it, end, &r)
|
||||
|| !plutovg_skip_ws_and_comma(&it, end)
|
||||
|| !parse_rgb_component(&it, end, &g)
|
||||
|| !plutovg_skip_ws_and_comma(&it, end)
|
||||
|| !parse_rgb_component(&it, end, &b)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(plutovg_skip_ws_and_comma(&it, end)
|
||||
&& !parse_alpha_component(&it, end, &a)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
plutovg_skip_ws(&it, end);
|
||||
if(!plutovg_skip_delim(&it, end, ')'))
|
||||
return 0;
|
||||
plutovg_color_init_rgba(color, r, g, b, a);
|
||||
} else if(strcmp(name, "hsl") == 0 || strcmp(name, "hsla") == 0) {
|
||||
if(!plutovg_skip_ws_and_delim(&it, end, '('))
|
||||
return 0;
|
||||
float h, s, l, a = 1.f;
|
||||
if(!plutovg_parse_number(&it, end, &h)
|
||||
|| !plutovg_skip_ws_and_comma(&it, end)
|
||||
|| !parse_alpha_component(&it, end, &s)
|
||||
|| !plutovg_skip_ws_and_comma(&it, end)
|
||||
|| !parse_alpha_component(&it, end, &l)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(plutovg_skip_ws_and_comma(&it, end)
|
||||
&& !parse_alpha_component(&it, end, &a)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
plutovg_skip_ws(&it, end);
|
||||
if(!plutovg_skip_delim(&it, end, ')'))
|
||||
return 0;
|
||||
plutovg_color_init_hsla(color, h, s, l, a);
|
||||
} else {
|
||||
static const color_entry_t colormap[] = {
|
||||
{"aliceblue", 0xF0F8FF},
|
||||
{"antiquewhite", 0xFAEBD7},
|
||||
{"aqua", 0x00FFFF},
|
||||
{"aquamarine", 0x7FFFD4},
|
||||
{"azure", 0xF0FFFF},
|
||||
{"beige", 0xF5F5DC},
|
||||
{"bisque", 0xFFE4C4},
|
||||
{"black", 0x000000},
|
||||
{"blanchedalmond", 0xFFEBCD},
|
||||
{"blue", 0x0000FF},
|
||||
{"blueviolet", 0x8A2BE2},
|
||||
{"brown", 0xA52A2A},
|
||||
{"burlywood", 0xDEB887},
|
||||
{"cadetblue", 0x5F9EA0},
|
||||
{"chartreuse", 0x7FFF00},
|
||||
{"chocolate", 0xD2691E},
|
||||
{"coral", 0xFF7F50},
|
||||
{"cornflowerblue", 0x6495ED},
|
||||
{"cornsilk", 0xFFF8DC},
|
||||
{"crimson", 0xDC143C},
|
||||
{"cyan", 0x00FFFF},
|
||||
{"darkblue", 0x00008B},
|
||||
{"darkcyan", 0x008B8B},
|
||||
{"darkgoldenrod", 0xB8860B},
|
||||
{"darkgray", 0xA9A9A9},
|
||||
{"darkgreen", 0x006400},
|
||||
{"darkgrey", 0xA9A9A9},
|
||||
{"darkkhaki", 0xBDB76B},
|
||||
{"darkmagenta", 0x8B008B},
|
||||
{"darkolivegreen", 0x556B2F},
|
||||
{"darkorange", 0xFF8C00},
|
||||
{"darkorchid", 0x9932CC},
|
||||
{"darkred", 0x8B0000},
|
||||
{"darksalmon", 0xE9967A},
|
||||
{"darkseagreen", 0x8FBC8F},
|
||||
{"darkslateblue", 0x483D8B},
|
||||
{"darkslategray", 0x2F4F4F},
|
||||
{"darkslategrey", 0x2F4F4F},
|
||||
{"darkturquoise", 0x00CED1},
|
||||
{"darkviolet", 0x9400D3},
|
||||
{"deeppink", 0xFF1493},
|
||||
{"deepskyblue", 0x00BFFF},
|
||||
{"dimgray", 0x696969},
|
||||
{"dimgrey", 0x696969},
|
||||
{"dodgerblue", 0x1E90FF},
|
||||
{"firebrick", 0xB22222},
|
||||
{"floralwhite", 0xFFFAF0},
|
||||
{"forestgreen", 0x228B22},
|
||||
{"fuchsia", 0xFF00FF},
|
||||
{"gainsboro", 0xDCDCDC},
|
||||
{"ghostwhite", 0xF8F8FF},
|
||||
{"gold", 0xFFD700},
|
||||
{"goldenrod", 0xDAA520},
|
||||
{"gray", 0x808080},
|
||||
{"green", 0x008000},
|
||||
{"greenyellow", 0xADFF2F},
|
||||
{"grey", 0x808080},
|
||||
{"honeydew", 0xF0FFF0},
|
||||
{"hotpink", 0xFF69B4},
|
||||
{"indianred", 0xCD5C5C},
|
||||
{"indigo", 0x4B0082},
|
||||
{"ivory", 0xFFFFF0},
|
||||
{"khaki", 0xF0E68C},
|
||||
{"lavender", 0xE6E6FA},
|
||||
{"lavenderblush", 0xFFF0F5},
|
||||
{"lawngreen", 0x7CFC00},
|
||||
{"lemonchiffon", 0xFFFACD},
|
||||
{"lightblue", 0xADD8E6},
|
||||
{"lightcoral", 0xF08080},
|
||||
{"lightcyan", 0xE0FFFF},
|
||||
{"lightgoldenrodyellow", 0xFAFAD2},
|
||||
{"lightgray", 0xD3D3D3},
|
||||
{"lightgreen", 0x90EE90},
|
||||
{"lightgrey", 0xD3D3D3},
|
||||
{"lightpink", 0xFFB6C1},
|
||||
{"lightsalmon", 0xFFA07A},
|
||||
{"lightseagreen", 0x20B2AA},
|
||||
{"lightskyblue", 0x87CEFA},
|
||||
{"lightslategray", 0x778899},
|
||||
{"lightslategrey", 0x778899},
|
||||
{"lightsteelblue", 0xB0C4DE},
|
||||
{"lightyellow", 0xFFFFE0},
|
||||
{"lime", 0x00FF00},
|
||||
{"limegreen", 0x32CD32},
|
||||
{"linen", 0xFAF0E6},
|
||||
{"magenta", 0xFF00FF},
|
||||
{"maroon", 0x800000},
|
||||
{"mediumaquamarine", 0x66CDAA},
|
||||
{"mediumblue", 0x0000CD},
|
||||
{"mediumorchid", 0xBA55D3},
|
||||
{"mediumpurple", 0x9370DB},
|
||||
{"mediumseagreen", 0x3CB371},
|
||||
{"mediumslateblue", 0x7B68EE},
|
||||
{"mediumspringgreen", 0x00FA9A},
|
||||
{"mediumturquoise", 0x48D1CC},
|
||||
{"mediumvioletred", 0xC71585},
|
||||
{"midnightblue", 0x191970},
|
||||
{"mintcream", 0xF5FFFA},
|
||||
{"mistyrose", 0xFFE4E1},
|
||||
{"moccasin", 0xFFE4B5},
|
||||
{"navajowhite", 0xFFDEAD},
|
||||
{"navy", 0x000080},
|
||||
{"oldlace", 0xFDF5E6},
|
||||
{"olive", 0x808000},
|
||||
{"olivedrab", 0x6B8E23},
|
||||
{"orange", 0xFFA500},
|
||||
{"orangered", 0xFF4500},
|
||||
{"orchid", 0xDA70D6},
|
||||
{"palegoldenrod", 0xEEE8AA},
|
||||
{"palegreen", 0x98FB98},
|
||||
{"paleturquoise", 0xAFEEEE},
|
||||
{"palevioletred", 0xDB7093},
|
||||
{"papayawhip", 0xFFEFD5},
|
||||
{"peachpuff", 0xFFDAB9},
|
||||
{"peru", 0xCD853F},
|
||||
{"pink", 0xFFC0CB},
|
||||
{"plum", 0xDDA0DD},
|
||||
{"powderblue", 0xB0E0E6},
|
||||
{"purple", 0x800080},
|
||||
{"rebeccapurple", 0x663399},
|
||||
{"red", 0xFF0000},
|
||||
{"rosybrown", 0xBC8F8F},
|
||||
{"royalblue", 0x4169E1},
|
||||
{"saddlebrown", 0x8B4513},
|
||||
{"salmon", 0xFA8072},
|
||||
{"sandybrown", 0xF4A460},
|
||||
{"seagreen", 0x2E8B57},
|
||||
{"seashell", 0xFFF5EE},
|
||||
{"sienna", 0xA0522D},
|
||||
{"silver", 0xC0C0C0},
|
||||
{"skyblue", 0x87CEEB},
|
||||
{"slateblue", 0x6A5ACD},
|
||||
{"slategray", 0x708090},
|
||||
{"slategrey", 0x708090},
|
||||
{"snow", 0xFFFAFA},
|
||||
{"springgreen", 0x00FF7F},
|
||||
{"steelblue", 0x4682B4},
|
||||
{"tan", 0xD2B48C},
|
||||
{"teal", 0x008080},
|
||||
{"thistle", 0xD8BFD8},
|
||||
{"tomato", 0xFF6347},
|
||||
{"turquoise", 0x40E0D0},
|
||||
{"violet", 0xEE82EE},
|
||||
{"wheat", 0xF5DEB3},
|
||||
{"white", 0xFFFFFF},
|
||||
{"whitesmoke", 0xF5F5F5},
|
||||
{"yellow", 0xFFFF00},
|
||||
{"yellowgreen", 0x9ACD32}
|
||||
};
|
||||
|
||||
const color_entry_t* entry = bsearch(name, colormap, sizeof(colormap) / sizeof(color_entry_t), sizeof(color_entry_t), color_entry_compare);
|
||||
if(entry == NULL)
|
||||
return 0;
|
||||
plutovg_color_init_argb32(color, 0xFF000000 | entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
plutovg_skip_ws(&it, end);
|
||||
return it - data;
|
||||
}
|
||||
|
||||
static void* plutovg_paint_create(plutovg_paint_type_t type, size_t size)
|
||||
{
|
||||
plutovg_paint_t* paint = malloc(size);
|
||||
paint->ref_count = 1;
|
||||
paint->type = type;
|
||||
return paint;
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_paint_create_rgb(float r, float g, float b)
|
||||
{
|
||||
return plutovg_paint_create_rgba(r, g, b, 1.f);
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_paint_create_rgba(float r, float g, float b, float a)
|
||||
{
|
||||
plutovg_solid_paint_t* solid = plutovg_paint_create(PLUTOVG_PAINT_TYPE_COLOR, sizeof(plutovg_solid_paint_t));
|
||||
solid->color.r = plutovg_clamp(r, 0.f, 1.f);
|
||||
solid->color.g = plutovg_clamp(g, 0.f, 1.f);
|
||||
solid->color.b = plutovg_clamp(b, 0.f, 1.f);
|
||||
solid->color.a = plutovg_clamp(a, 0.f, 1.f);
|
||||
return &solid->base;
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_paint_create_color(const plutovg_color_t* color)
|
||||
{
|
||||
return plutovg_paint_create_rgba(color->r, color->g, color->b, color->a);
|
||||
}
|
||||
|
||||
static plutovg_gradient_paint_t* plutovg_gradient_create(plutovg_gradient_type_t type, plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix)
|
||||
{
|
||||
plutovg_gradient_paint_t* gradient = plutovg_paint_create(PLUTOVG_PAINT_TYPE_GRADIENT, sizeof(plutovg_gradient_paint_t) + nstops * sizeof(plutovg_gradient_stop_t));
|
||||
gradient->type = type;
|
||||
gradient->spread = spread;
|
||||
gradient->matrix = matrix ? *matrix : PLUTOVG_IDENTITY_MATRIX;
|
||||
gradient->stops = (plutovg_gradient_stop_t*)(gradient + 1);
|
||||
gradient->nstops = nstops;
|
||||
|
||||
float prev_offset = 0.f;
|
||||
for(int i = 0; i < nstops; ++i) {
|
||||
const plutovg_gradient_stop_t* stop = stops + i;
|
||||
gradient->stops[i].offset = plutovg_max(prev_offset, plutovg_clamp(stop->offset, 0.f, 1.f));
|
||||
gradient->stops[i].color.r = plutovg_clamp(stop->color.r, 0.f, 1.f);
|
||||
gradient->stops[i].color.g = plutovg_clamp(stop->color.g, 0.f, 1.f);
|
||||
gradient->stops[i].color.b = plutovg_clamp(stop->color.b, 0.f, 1.f);
|
||||
gradient->stops[i].color.a = plutovg_clamp(stop->color.a, 0.f, 1.f);
|
||||
prev_offset = gradient->stops[i].offset;
|
||||
}
|
||||
|
||||
return gradient;
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_paint_create_linear_gradient(float x1, float y1, float x2, float y2, plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix)
|
||||
{
|
||||
plutovg_gradient_paint_t* gradient = plutovg_gradient_create(PLUTOVG_GRADIENT_TYPE_LINEAR, spread, stops, nstops, matrix);
|
||||
gradient->values[0] = x1;
|
||||
gradient->values[1] = y1;
|
||||
gradient->values[2] = x2;
|
||||
gradient->values[3] = y2;
|
||||
return &gradient->base;
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_paint_create_radial_gradient(float cx, float cy, float cr, float fx, float fy, float fr, plutovg_spread_method_t spread, const plutovg_gradient_stop_t* stops, int nstops, const plutovg_matrix_t* matrix)
|
||||
{
|
||||
plutovg_gradient_paint_t* gradient = plutovg_gradient_create(PLUTOVG_GRADIENT_TYPE_RADIAL, spread, stops, nstops, matrix);
|
||||
gradient->values[0] = cx;
|
||||
gradient->values[1] = cy;
|
||||
gradient->values[2] = cr;
|
||||
gradient->values[3] = fx;
|
||||
gradient->values[4] = fy;
|
||||
gradient->values[5] = fr;
|
||||
return &gradient->base;
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_paint_create_texture(plutovg_surface_t* surface, plutovg_texture_type_t type, float opacity, const plutovg_matrix_t* matrix)
|
||||
{
|
||||
plutovg_texture_paint_t* texture = plutovg_paint_create(PLUTOVG_PAINT_TYPE_TEXTURE, sizeof(plutovg_texture_paint_t));
|
||||
texture->type = type;
|
||||
texture->opacity = plutovg_clamp(opacity, 0.f, 1.f);
|
||||
texture->matrix = matrix ? *matrix : PLUTOVG_IDENTITY_MATRIX;
|
||||
texture->surface = plutovg_surface_reference(surface);
|
||||
return &texture->base;
|
||||
}
|
||||
|
||||
plutovg_paint_t* plutovg_paint_reference(plutovg_paint_t* paint)
|
||||
{
|
||||
if(paint == NULL)
|
||||
return NULL;
|
||||
++paint->ref_count;
|
||||
return paint;
|
||||
}
|
||||
|
||||
void plutovg_paint_destroy(plutovg_paint_t* paint)
|
||||
{
|
||||
if(paint == NULL)
|
||||
return;
|
||||
if(--paint->ref_count == 0) {
|
||||
if(paint->type == PLUTOVG_PAINT_TYPE_TEXTURE) {
|
||||
plutovg_texture_paint_t* texture = (plutovg_texture_paint_t*)(paint);
|
||||
plutovg_surface_destroy(texture->surface);
|
||||
}
|
||||
|
||||
free(paint);
|
||||
}
|
||||
}
|
||||
|
||||
int plutovg_paint_get_reference_count(const plutovg_paint_t* paint)
|
||||
{
|
||||
if(paint)
|
||||
return paint->ref_count;
|
||||
return 0;
|
||||
}
|
||||
924
3rdparty/plutosvg/plutovg/source/plutovg-path.c
vendored
Normal file
924
3rdparty/plutosvg/plutovg/source/plutovg-path.c
vendored
Normal file
@@ -0,0 +1,924 @@
|
||||
#include "plutovg-private.h"
|
||||
#include "plutovg-utils.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
void plutovg_path_iterator_init(plutovg_path_iterator_t* it, const plutovg_path_t* path)
|
||||
{
|
||||
it->elements = path->elements.data;
|
||||
it->size = path->elements.size;
|
||||
it->index = 0;
|
||||
}
|
||||
|
||||
bool plutovg_path_iterator_has_next(const plutovg_path_iterator_t* it)
|
||||
{
|
||||
return it->index < it->size;
|
||||
}
|
||||
|
||||
plutovg_path_command_t plutovg_path_iterator_next(plutovg_path_iterator_t* it, plutovg_point_t points[3])
|
||||
{
|
||||
const plutovg_path_element_t* elements = it->elements + it->index;
|
||||
switch(elements[0].header.command) {
|
||||
case PLUTOVG_PATH_COMMAND_MOVE_TO:
|
||||
case PLUTOVG_PATH_COMMAND_LINE_TO:
|
||||
case PLUTOVG_PATH_COMMAND_CLOSE:
|
||||
points[0] = elements[1].point;
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CUBIC_TO:
|
||||
points[0] = elements[1].point;
|
||||
points[1] = elements[2].point;
|
||||
points[2] = elements[3].point;
|
||||
break;
|
||||
}
|
||||
|
||||
it->index += elements[0].header.length;
|
||||
return elements[0].header.command;
|
||||
}
|
||||
|
||||
plutovg_path_t* plutovg_path_create(void)
|
||||
{
|
||||
plutovg_path_t* path = malloc(sizeof(plutovg_path_t));
|
||||
path->ref_count = 1;
|
||||
path->num_points = 0;
|
||||
path->num_contours = 0;
|
||||
path->num_curves = 0;
|
||||
path->start_point = PLUTOVG_MAKE_POINT(0, 0);
|
||||
plutovg_array_init(path->elements);
|
||||
return path;
|
||||
}
|
||||
|
||||
plutovg_path_t* plutovg_path_reference(plutovg_path_t* path)
|
||||
{
|
||||
if(path == NULL)
|
||||
return NULL;
|
||||
++path->ref_count;
|
||||
return path;
|
||||
}
|
||||
|
||||
void plutovg_path_destroy(plutovg_path_t* path)
|
||||
{
|
||||
if(path == NULL)
|
||||
return;
|
||||
if(--path->ref_count == 0) {
|
||||
plutovg_array_destroy(path->elements);
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
|
||||
int plutovg_path_get_reference_count(const plutovg_path_t* path)
|
||||
{
|
||||
if(path)
|
||||
return path->ref_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plutovg_path_get_elements(const plutovg_path_t* path, const plutovg_path_element_t** elements)
|
||||
{
|
||||
if(elements)
|
||||
*elements = path->elements.data;
|
||||
return path->elements.size;
|
||||
}
|
||||
|
||||
static plutovg_path_element_t* plutovg_path_add_command(plutovg_path_t* path, plutovg_path_command_t command, int npoints)
|
||||
{
|
||||
const int length = npoints + 1;
|
||||
plutovg_array_ensure(path->elements, length);
|
||||
plutovg_path_element_t* elements = path->elements.data + path->elements.size;
|
||||
elements->header.command = command;
|
||||
elements->header.length = length;
|
||||
path->elements.size += length;
|
||||
path->num_points += npoints;
|
||||
return elements + 1;
|
||||
}
|
||||
|
||||
void plutovg_path_move_to(plutovg_path_t* path, float x, float y)
|
||||
{
|
||||
plutovg_path_element_t* elements = plutovg_path_add_command(path, PLUTOVG_PATH_COMMAND_MOVE_TO, 1);
|
||||
elements[0].point = PLUTOVG_MAKE_POINT(x, y);
|
||||
path->start_point = PLUTOVG_MAKE_POINT(x, y);
|
||||
path->num_contours += 1;
|
||||
}
|
||||
|
||||
void plutovg_path_line_to(plutovg_path_t* path, float x, float y)
|
||||
{
|
||||
if(path->elements.size == 0)
|
||||
plutovg_path_move_to(path, 0, 0);
|
||||
plutovg_path_element_t* elements = plutovg_path_add_command(path, PLUTOVG_PATH_COMMAND_LINE_TO, 1);
|
||||
elements[0].point = PLUTOVG_MAKE_POINT(x, y);
|
||||
}
|
||||
|
||||
void plutovg_path_quad_to(plutovg_path_t* path, float x1, float y1, float x2, float y2)
|
||||
{
|
||||
float current_x, current_y;
|
||||
plutovg_path_get_current_point(path, ¤t_x, ¤t_y);
|
||||
float cp1x = 2.f / 3.f * x1 + 1.f / 3.f * current_x;
|
||||
float cp1y = 2.f / 3.f * y1 + 1.f / 3.f * current_y;
|
||||
float cp2x = 2.f / 3.f * x1 + 1.f / 3.f * x2;
|
||||
float cp2y = 2.f / 3.f * y1 + 1.f / 3.f * y2;
|
||||
plutovg_path_cubic_to(path, cp1x, cp1y, cp2x, cp2y, x2, y2);
|
||||
}
|
||||
|
||||
void plutovg_path_cubic_to(plutovg_path_t* path, float x1, float y1, float x2, float y2, float x3, float y3)
|
||||
{
|
||||
if(path->elements.size == 0)
|
||||
plutovg_path_move_to(path, 0, 0);
|
||||
plutovg_path_element_t* elements = plutovg_path_add_command(path, PLUTOVG_PATH_COMMAND_CUBIC_TO, 3);
|
||||
elements[0].point = PLUTOVG_MAKE_POINT(x1, y1);
|
||||
elements[1].point = PLUTOVG_MAKE_POINT(x2, y2);
|
||||
elements[2].point = PLUTOVG_MAKE_POINT(x3, y3);
|
||||
path->num_curves += 1;
|
||||
}
|
||||
|
||||
void plutovg_path_arc_to(plutovg_path_t* path, float rx, float ry, float angle, bool large_arc_flag, bool sweep_flag, float x, float y)
|
||||
{
|
||||
float current_x, current_y;
|
||||
plutovg_path_get_current_point(path, ¤t_x, ¤t_y);
|
||||
if(rx == 0.f || ry == 0.f || (current_x == x && current_y == y)) {
|
||||
plutovg_path_line_to(path, x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
if(rx < 0.f) rx = -rx;
|
||||
if(ry < 0.f) ry = -ry;
|
||||
|
||||
float dx = (current_x - x) * 0.5f;
|
||||
float dy = (current_y - y) * 0.5f;
|
||||
|
||||
plutovg_matrix_t matrix;
|
||||
plutovg_matrix_init_rotate(&matrix, -angle);
|
||||
plutovg_matrix_map(&matrix, dx, dy, &dx, &dy);
|
||||
|
||||
float rxrx = rx * rx;
|
||||
float ryry = ry * ry;
|
||||
float dxdx = dx * dx;
|
||||
float dydy = dy * dy;
|
||||
float radius = dxdx / rxrx + dydy / ryry;
|
||||
if(radius > 1.f) {
|
||||
rx *= sqrtf(radius);
|
||||
ry *= sqrtf(radius);
|
||||
}
|
||||
|
||||
plutovg_matrix_init_scale(&matrix, 1.f / rx, 1.f / ry);
|
||||
plutovg_matrix_rotate(&matrix, -angle);
|
||||
|
||||
float x1, y1;
|
||||
float x2, y2;
|
||||
plutovg_matrix_map(&matrix, current_x, current_y, &x1, &y1);
|
||||
plutovg_matrix_map(&matrix, x, y, &x2, &y2);
|
||||
|
||||
float dx1 = x2 - x1;
|
||||
float dy1 = y2 - y1;
|
||||
float d = dx1 * dx1 + dy1 * dy1;
|
||||
float scale_sq = 1.f / d - 0.25f;
|
||||
if(scale_sq < 0.f) scale_sq = 0.f;
|
||||
float scale = sqrtf(scale_sq);
|
||||
if(sweep_flag == large_arc_flag)
|
||||
scale = -scale;
|
||||
dx1 *= scale;
|
||||
dy1 *= scale;
|
||||
|
||||
float cx1 = 0.5f * (x1 + x2) - dy1;
|
||||
float cy1 = 0.5f * (y1 + y2) + dx1;
|
||||
|
||||
float th1 = atan2f(y1 - cy1, x1 - cx1);
|
||||
float th2 = atan2f(y2 - cy1, x2 - cx1);
|
||||
float th_arc = th2 - th1;
|
||||
if(th_arc < 0.f && sweep_flag)
|
||||
th_arc += PLUTOVG_TWO_PI;
|
||||
else if(th_arc > 0.f && !sweep_flag)
|
||||
th_arc -= PLUTOVG_TWO_PI;
|
||||
plutovg_matrix_init_rotate(&matrix, angle);
|
||||
plutovg_matrix_scale(&matrix, rx, ry);
|
||||
int segments = (int)(ceilf(fabsf(th_arc / (PLUTOVG_HALF_PI + 0.001f))));
|
||||
for(int i = 0; i < segments; i++) {
|
||||
float th_start = th1 + i * th_arc / segments;
|
||||
float th_end = th1 + (i + 1) * th_arc / segments;
|
||||
float t = (8.f / 6.f) * tanf(0.25f * (th_end - th_start));
|
||||
|
||||
float x3 = cosf(th_end) + cx1;
|
||||
float y3 = sinf(th_end) + cy1;
|
||||
|
||||
float cp2x = x3 + t * sinf(th_end);
|
||||
float cp2y = y3 - t * cosf(th_end);
|
||||
|
||||
float cp1x = cosf(th_start) - t * sinf(th_start);
|
||||
float cp1y = sinf(th_start) + t * cosf(th_start);
|
||||
|
||||
cp1x += cx1;
|
||||
cp1y += cy1;
|
||||
|
||||
plutovg_matrix_map(&matrix, cp1x, cp1y, &cp1x, &cp1y);
|
||||
plutovg_matrix_map(&matrix, cp2x, cp2y, &cp2x, &cp2y);
|
||||
plutovg_matrix_map(&matrix, x3, y3, &x3, &y3);
|
||||
|
||||
plutovg_path_cubic_to(path, cp1x, cp1y, cp2x, cp2y, x3, y3);
|
||||
}
|
||||
}
|
||||
|
||||
void plutovg_path_close(plutovg_path_t* path)
|
||||
{
|
||||
if(path->elements.size == 0)
|
||||
return;
|
||||
plutovg_path_element_t* elements = plutovg_path_add_command(path, PLUTOVG_PATH_COMMAND_CLOSE, 1);
|
||||
elements[0].point = path->start_point;
|
||||
}
|
||||
|
||||
void plutovg_path_get_current_point(const plutovg_path_t* path, float* x, float* y)
|
||||
{
|
||||
float xx = 0.f;
|
||||
float yy = 0.f;
|
||||
if(path->num_points > 0) {
|
||||
xx = path->elements.data[path->elements.size - 1].point.x;
|
||||
yy = path->elements.data[path->elements.size - 1].point.y;
|
||||
}
|
||||
|
||||
if(x) *x = xx;
|
||||
if(y) *y = yy;
|
||||
}
|
||||
|
||||
void plutovg_path_reserve(plutovg_path_t* path, int count)
|
||||
{
|
||||
plutovg_array_ensure(path->elements, count);
|
||||
}
|
||||
|
||||
void plutovg_path_reset(plutovg_path_t* path)
|
||||
{
|
||||
plutovg_array_clear(path->elements);
|
||||
path->start_point = PLUTOVG_MAKE_POINT(0, 0);
|
||||
path->num_points = 0;
|
||||
path->num_contours = 0;
|
||||
path->num_curves = 0;
|
||||
}
|
||||
|
||||
void plutovg_path_add_rect(plutovg_path_t* path, float x, float y, float w, float h)
|
||||
{
|
||||
plutovg_path_reserve(path, 6 * 2);
|
||||
plutovg_path_move_to(path, x, y);
|
||||
plutovg_path_line_to(path, x + w, y);
|
||||
plutovg_path_line_to(path, x + w, y + h);
|
||||
plutovg_path_line_to(path, x, y + h);
|
||||
plutovg_path_line_to(path, x, y);
|
||||
plutovg_path_close(path);
|
||||
}
|
||||
|
||||
void plutovg_path_add_round_rect(plutovg_path_t* path, float x, float y, float w, float h, float rx, float ry)
|
||||
{
|
||||
rx = plutovg_min(rx, w * 0.5f);
|
||||
ry = plutovg_min(ry, h * 0.5f);
|
||||
if(rx == 0.f && ry == 0.f) {
|
||||
plutovg_path_add_rect(path, x, y, w, h);
|
||||
return;
|
||||
}
|
||||
|
||||
float right = x + w;
|
||||
float bottom = y + h;
|
||||
|
||||
float cpx = rx * PLUTOVG_KAPPA;
|
||||
float cpy = ry * PLUTOVG_KAPPA;
|
||||
|
||||
plutovg_path_reserve(path, 6 * 2 + 4 * 4);
|
||||
plutovg_path_move_to(path, x, y+ry);
|
||||
plutovg_path_cubic_to(path, x, y+ry-cpy, x+rx-cpx, y, x+rx, y);
|
||||
plutovg_path_line_to(path, right-rx, y);
|
||||
plutovg_path_cubic_to(path, right-rx+cpx, y, right, y+ry-cpy, right, y+ry);
|
||||
plutovg_path_line_to(path, right, bottom-ry);
|
||||
plutovg_path_cubic_to(path, right, bottom-ry+cpy, right-rx+cpx, bottom, right-rx, bottom);
|
||||
plutovg_path_line_to(path, x+rx, bottom);
|
||||
plutovg_path_cubic_to(path, x+rx-cpx, bottom, x, bottom-ry+cpy, x, bottom-ry);
|
||||
plutovg_path_line_to(path, x, y+ry);
|
||||
plutovg_path_close(path);
|
||||
}
|
||||
|
||||
void plutovg_path_add_ellipse(plutovg_path_t* path, float cx, float cy, float rx, float ry)
|
||||
{
|
||||
float left = cx - rx;
|
||||
float top = cy - ry;
|
||||
float right = cx + rx;
|
||||
float bottom = cy + ry;
|
||||
|
||||
float cpx = rx * PLUTOVG_KAPPA;
|
||||
float cpy = ry * PLUTOVG_KAPPA;
|
||||
|
||||
plutovg_path_reserve(path, 2 * 2 + 4 * 4);
|
||||
plutovg_path_move_to(path, cx, top);
|
||||
plutovg_path_cubic_to(path, cx+cpx, top, right, cy-cpy, right, cy);
|
||||
plutovg_path_cubic_to(path, right, cy+cpy, cx+cpx, bottom, cx, bottom);
|
||||
plutovg_path_cubic_to(path, cx-cpx, bottom, left, cy+cpy, left, cy);
|
||||
plutovg_path_cubic_to(path, left, cy-cpy, cx-cpx, top, cx, top);
|
||||
plutovg_path_close(path);
|
||||
}
|
||||
|
||||
void plutovg_path_add_circle(plutovg_path_t* path, float cx, float cy, float r)
|
||||
{
|
||||
plutovg_path_add_ellipse(path, cx, cy, r, r);
|
||||
}
|
||||
|
||||
void plutovg_path_add_arc(plutovg_path_t* path, float cx, float cy, float r, float a0, float a1, bool ccw)
|
||||
{
|
||||
float da = a1 - a0;
|
||||
if(fabsf(da) > PLUTOVG_TWO_PI) {
|
||||
da = PLUTOVG_TWO_PI;
|
||||
} else if(da != 0.f && ccw != (da < 0.f)) {
|
||||
da += PLUTOVG_TWO_PI * (ccw ? -1 : 1);
|
||||
}
|
||||
|
||||
int seg_n = (int)(ceilf(fabsf(da) / PLUTOVG_HALF_PI));
|
||||
if(seg_n == 0)
|
||||
return;
|
||||
float a = a0;
|
||||
float ax = cx + cosf(a) * r;
|
||||
float ay = cy + sinf(a) * r;
|
||||
|
||||
float seg_a = da / seg_n;
|
||||
float d = (seg_a / PLUTOVG_HALF_PI) * PLUTOVG_KAPPA * r;
|
||||
float dx = -sinf(a) * d;
|
||||
float dy = cosf(a) * d;
|
||||
|
||||
plutovg_path_reserve(path, 2 + 4 * seg_n);
|
||||
if(path->elements.size == 0) {
|
||||
plutovg_path_move_to(path, ax, ay);
|
||||
} else {
|
||||
plutovg_path_line_to(path, ax, ay);
|
||||
}
|
||||
|
||||
for(int i = 0; i < seg_n; i++) {
|
||||
float cp1x = ax + dx;
|
||||
float cp1y = ay + dy;
|
||||
|
||||
a += seg_a;
|
||||
ax = cx + cosf(a) * r;
|
||||
ay = cy + sinf(a) * r;
|
||||
|
||||
dx = -sinf(a) * d;
|
||||
dy = cosf(a) * d;
|
||||
|
||||
float cp2x = ax - dx;
|
||||
float cp2y = ay - dy;
|
||||
|
||||
plutovg_path_cubic_to(path, cp1x, cp1y, cp2x, cp2y, ax, ay);
|
||||
}
|
||||
}
|
||||
|
||||
void plutovg_path_transform(plutovg_path_t* path, const plutovg_matrix_t* matrix)
|
||||
{
|
||||
plutovg_path_element_t* elements = path->elements.data;
|
||||
for(int i = 0; i < path->elements.size; i += elements[i].header.length) {
|
||||
switch(elements[i].header.command) {
|
||||
case PLUTOVG_PATH_COMMAND_MOVE_TO:
|
||||
case PLUTOVG_PATH_COMMAND_LINE_TO:
|
||||
case PLUTOVG_PATH_COMMAND_CLOSE:
|
||||
plutovg_matrix_map_point(matrix, &elements[i + 1].point, &elements[i + 1].point);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CUBIC_TO:
|
||||
plutovg_matrix_map_point(matrix, &elements[i + 1].point, &elements[i + 1].point);
|
||||
plutovg_matrix_map_point(matrix, &elements[i + 2].point, &elements[i + 2].point);
|
||||
plutovg_matrix_map_point(matrix, &elements[i + 3].point, &elements[i + 3].point);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void plutovg_path_add_path(plutovg_path_t* path, const plutovg_path_t* source, const plutovg_matrix_t* matrix)
|
||||
{
|
||||
if(matrix == NULL) {
|
||||
plutovg_array_append(path->elements, source->elements);
|
||||
path->start_point = source->start_point;
|
||||
path->num_points += source->num_points;
|
||||
path->num_contours += source->num_contours;
|
||||
path->num_curves += source->num_curves;
|
||||
return;
|
||||
}
|
||||
|
||||
plutovg_path_iterator_t it;
|
||||
plutovg_path_iterator_init(&it, source);
|
||||
|
||||
plutovg_point_t points[3];
|
||||
plutovg_array_ensure(path->elements, source->elements.size);
|
||||
while(plutovg_path_iterator_has_next(&it)) {
|
||||
switch(plutovg_path_iterator_next(&it, points)) {
|
||||
case PLUTOVG_PATH_COMMAND_MOVE_TO:
|
||||
plutovg_matrix_map_points(matrix, points, points, 1);
|
||||
plutovg_path_move_to(path, points[0].x, points[0].y);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_LINE_TO:
|
||||
plutovg_matrix_map_points(matrix, points, points, 1);
|
||||
plutovg_path_line_to(path, points[0].x, points[0].y);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CUBIC_TO:
|
||||
plutovg_matrix_map_points(matrix, points, points, 3);
|
||||
plutovg_path_cubic_to(path, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CLOSE:
|
||||
plutovg_path_close(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void plutovg_path_traverse(const plutovg_path_t* path, plutovg_path_traverse_func_t traverse_func, void* closure)
|
||||
{
|
||||
plutovg_path_iterator_t it;
|
||||
plutovg_path_iterator_init(&it, path);
|
||||
|
||||
plutovg_point_t points[3];
|
||||
while(plutovg_path_iterator_has_next(&it)) {
|
||||
switch(plutovg_path_iterator_next(&it, points)) {
|
||||
case PLUTOVG_PATH_COMMAND_MOVE_TO:
|
||||
traverse_func(closure, PLUTOVG_PATH_COMMAND_MOVE_TO, points, 1);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_LINE_TO:
|
||||
traverse_func(closure, PLUTOVG_PATH_COMMAND_LINE_TO, points, 1);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CUBIC_TO:
|
||||
traverse_func(closure, PLUTOVG_PATH_COMMAND_CUBIC_TO, points, 3);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CLOSE:
|
||||
traverse_func(closure, PLUTOVG_PATH_COMMAND_CLOSE, points, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
float x1; float y1;
|
||||
float x2; float y2;
|
||||
float x3; float y3;
|
||||
float x4; float y4;
|
||||
} bezier_t;
|
||||
|
||||
static inline void split_bezier(const bezier_t* b, bezier_t* first, bezier_t* second)
|
||||
{
|
||||
float c = (b->x2 + b->x3) * 0.5f;
|
||||
first->x2 = (b->x1 + b->x2) * 0.5f;
|
||||
second->x3 = (b->x3 + b->x4) * 0.5f;
|
||||
first->x1 = b->x1;
|
||||
second->x4 = b->x4;
|
||||
first->x3 = (first->x2 + c) * 0.5f;
|
||||
second->x2 = (second->x3 + c) * 0.5f;
|
||||
first->x4 = second->x1 = (first->x3 + second->x2) * 0.5f;
|
||||
|
||||
c = (b->y2 + b->y3) * 0.5f;
|
||||
first->y2 = (b->y1 + b->y2) * 0.5f;
|
||||
second->y3 = (b->y3 + b->y4) * 0.5f;
|
||||
first->y1 = b->y1;
|
||||
second->y4 = b->y4;
|
||||
first->y3 = (first->y2 + c) * 0.5f;
|
||||
second->y2 = (second->y3 + c) * 0.5f;
|
||||
first->y4 = second->y1 = (first->y3 + second->y2) * 0.5f;
|
||||
}
|
||||
|
||||
void plutovg_path_traverse_flatten(const plutovg_path_t* path, plutovg_path_traverse_func_t traverse_func, void* closure)
|
||||
{
|
||||
if(path->num_curves == 0) {
|
||||
plutovg_path_traverse(path, traverse_func, closure);
|
||||
return;
|
||||
}
|
||||
|
||||
const float threshold = 0.25f;
|
||||
|
||||
plutovg_path_iterator_t it;
|
||||
plutovg_path_iterator_init(&it, path);
|
||||
|
||||
bezier_t beziers[32];
|
||||
plutovg_point_t points[3];
|
||||
plutovg_point_t current_point = {0, 0};
|
||||
while(plutovg_path_iterator_has_next(&it)) {
|
||||
plutovg_path_command_t command = plutovg_path_iterator_next(&it, points);
|
||||
switch(command) {
|
||||
case PLUTOVG_PATH_COMMAND_MOVE_TO:
|
||||
case PLUTOVG_PATH_COMMAND_LINE_TO:
|
||||
case PLUTOVG_PATH_COMMAND_CLOSE:
|
||||
traverse_func(closure, command, points, 1);
|
||||
current_point = points[0];
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CUBIC_TO:
|
||||
beziers[0].x1 = current_point.x;
|
||||
beziers[0].y1 = current_point.y;
|
||||
beziers[0].x2 = points[0].x;
|
||||
beziers[0].y2 = points[0].y;
|
||||
beziers[0].x3 = points[1].x;
|
||||
beziers[0].y3 = points[1].y;
|
||||
beziers[0].x4 = points[2].x;
|
||||
beziers[0].y4 = points[2].y;
|
||||
bezier_t* b = beziers;
|
||||
while(b >= beziers) {
|
||||
float y4y1 = b->y4 - b->y1;
|
||||
float x4x1 = b->x4 - b->x1;
|
||||
float l = fabsf(x4x1) + fabsf(y4y1);
|
||||
float d;
|
||||
if(l > 1.f) {
|
||||
d = fabsf((x4x1)*(b->y1 - b->y2) - (y4y1)*(b->x1 - b->x2)) + fabsf((x4x1)*(b->y1 - b->y3) - (y4y1)*(b->x1 - b->x3));
|
||||
} else {
|
||||
d = fabsf(b->x1 - b->x2) + fabsf(b->y1 - b->y2) + fabsf(b->x1 - b->x3) + fabsf(b->y1 - b->y3);
|
||||
l = 1.f;
|
||||
}
|
||||
|
||||
if(d < threshold*l || b == beziers + 31) {
|
||||
plutovg_point_t p = { b->x4, b->y4 };
|
||||
traverse_func(closure, PLUTOVG_PATH_COMMAND_LINE_TO, &p, 1);
|
||||
--b;
|
||||
} else {
|
||||
split_bezier(b, b + 1, b);
|
||||
++b;
|
||||
}
|
||||
}
|
||||
|
||||
current_point = points[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const float* dashes; int ndashes;
|
||||
float start_phase; float phase;
|
||||
int start_index; int index;
|
||||
bool start_toggle; bool toggle;
|
||||
plutovg_point_t current_point;
|
||||
plutovg_path_traverse_func_t traverse_func;
|
||||
void* closure;
|
||||
} dasher_t;
|
||||
|
||||
static void dash_traverse_func(void* closure, plutovg_path_command_t command, const plutovg_point_t* points, int npoints)
|
||||
{
|
||||
dasher_t* dasher = (dasher_t*)(closure);
|
||||
if(command == PLUTOVG_PATH_COMMAND_MOVE_TO) {
|
||||
if(dasher->start_toggle)
|
||||
dasher->traverse_func(dasher->closure, PLUTOVG_PATH_COMMAND_MOVE_TO, points, npoints);
|
||||
dasher->current_point = points[0];
|
||||
dasher->phase = dasher->start_phase;
|
||||
dasher->index = dasher->start_index;
|
||||
dasher->toggle = dasher->start_toggle;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(command == PLUTOVG_PATH_COMMAND_LINE_TO || command == PLUTOVG_PATH_COMMAND_CLOSE);
|
||||
plutovg_point_t p0 = dasher->current_point;
|
||||
plutovg_point_t p1 = points[0];
|
||||
float dx = p1.x - p0.x;
|
||||
float dy = p1.y - p0.y;
|
||||
float dist0 = sqrtf(dx*dx + dy*dy);
|
||||
float dist1 = 0.f;
|
||||
while(dist0 - dist1 > dasher->dashes[dasher->index % dasher->ndashes] - dasher->phase) {
|
||||
dist1 += dasher->dashes[dasher->index % dasher->ndashes] - dasher->phase;
|
||||
float a = dist1 / dist0;
|
||||
plutovg_point_t p = { p0.x + a * dx, p0.y + a * dy };
|
||||
if(dasher->toggle) {
|
||||
dasher->traverse_func(dasher->closure, PLUTOVG_PATH_COMMAND_LINE_TO, &p, 1);
|
||||
} else {
|
||||
dasher->traverse_func(dasher->closure, PLUTOVG_PATH_COMMAND_MOVE_TO, &p, 1);
|
||||
}
|
||||
|
||||
dasher->phase = 0.f;
|
||||
dasher->toggle = !dasher->toggle;
|
||||
dasher->index++;
|
||||
}
|
||||
|
||||
if(dasher->toggle) {
|
||||
dasher->traverse_func(dasher->closure, PLUTOVG_PATH_COMMAND_LINE_TO, &p1, 1);
|
||||
}
|
||||
|
||||
dasher->phase += dist0 - dist1;
|
||||
dasher->current_point = p1;
|
||||
}
|
||||
|
||||
void plutovg_path_traverse_dashed(const plutovg_path_t* path, float offset, const float* dashes, int ndashes, plutovg_path_traverse_func_t traverse_func, void* closure)
|
||||
{
|
||||
float dash_sum = 0.f;
|
||||
for(int i = 0; i < ndashes; ++i)
|
||||
dash_sum += dashes[i];
|
||||
if(ndashes % 2 == 1)
|
||||
dash_sum *= 2.f;
|
||||
if(dash_sum <= 0.f) {
|
||||
plutovg_path_traverse(path, traverse_func, closure);
|
||||
return;
|
||||
}
|
||||
|
||||
dasher_t dasher;
|
||||
dasher.dashes = dashes;
|
||||
dasher.ndashes = ndashes;
|
||||
dasher.start_phase = fmodf(offset, dash_sum);
|
||||
if(dasher.start_phase < 0.f)
|
||||
dasher.start_phase += dash_sum;
|
||||
dasher.start_index = 0;
|
||||
dasher.start_toggle = true;
|
||||
while(dasher.start_phase > 0.f && dasher.start_phase >= dasher.dashes[dasher.start_index % dasher.ndashes]) {
|
||||
dasher.start_phase -= dashes[dasher.start_index % dasher.ndashes];
|
||||
dasher.start_toggle = !dasher.start_toggle;
|
||||
dasher.start_index++;
|
||||
}
|
||||
|
||||
dasher.phase = dasher.start_phase;
|
||||
dasher.index = dasher.start_index;
|
||||
dasher.toggle = dasher.start_toggle;
|
||||
dasher.current_point = PLUTOVG_MAKE_POINT(0, 0);
|
||||
dasher.traverse_func = traverse_func;
|
||||
dasher.closure = closure;
|
||||
plutovg_path_traverse_flatten(path, dash_traverse_func, &dasher);
|
||||
}
|
||||
|
||||
plutovg_path_t* plutovg_path_clone(const plutovg_path_t* path)
|
||||
{
|
||||
plutovg_path_t* clone = plutovg_path_create();
|
||||
plutovg_array_append(clone->elements, path->elements);
|
||||
clone->start_point = path->start_point;
|
||||
clone->num_points = path->num_points;
|
||||
clone->num_contours = path->num_contours;
|
||||
clone->num_curves = path->num_curves;
|
||||
return clone;
|
||||
}
|
||||
|
||||
static void clone_traverse_func(void* closure, plutovg_path_command_t command, const plutovg_point_t* points, int npoints)
|
||||
{
|
||||
plutovg_path_t* path = (plutovg_path_t*)(closure);
|
||||
switch(command) {
|
||||
case PLUTOVG_PATH_COMMAND_MOVE_TO:
|
||||
plutovg_path_move_to(path, points[0].x, points[0].y);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_LINE_TO:
|
||||
plutovg_path_line_to(path, points[0].x, points[0].y);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CUBIC_TO:
|
||||
plutovg_path_cubic_to(path, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CLOSE:
|
||||
plutovg_path_close(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
plutovg_path_t* plutovg_path_clone_flatten(const plutovg_path_t* path)
|
||||
{
|
||||
plutovg_path_t* clone = plutovg_path_create();
|
||||
plutovg_path_reserve(clone, path->elements.size + path->num_curves * 32);
|
||||
plutovg_path_traverse_flatten(path, clone_traverse_func, clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
plutovg_path_t* plutovg_path_clone_dashed(const plutovg_path_t* path, float offset, const float* dashes, int ndashes)
|
||||
{
|
||||
plutovg_path_t* clone = plutovg_path_create();
|
||||
plutovg_path_reserve(clone, path->elements.size + path->num_curves * 32);
|
||||
plutovg_path_traverse_dashed(path, offset, dashes, ndashes, clone_traverse_func, clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
plutovg_point_t current_point;
|
||||
bool is_first_point;
|
||||
float length;
|
||||
float x1;
|
||||
float y1;
|
||||
float x2;
|
||||
float y2;
|
||||
} extents_calculator_t;
|
||||
|
||||
static void extents_traverse_func(void* closure, plutovg_path_command_t command, const plutovg_point_t* points, int npoints)
|
||||
{
|
||||
extents_calculator_t* calculator = (extents_calculator_t*)(closure);
|
||||
if(calculator->is_first_point) {
|
||||
assert(command == PLUTOVG_PATH_COMMAND_MOVE_TO);
|
||||
calculator->is_first_point = false;
|
||||
calculator->current_point = points[0];
|
||||
calculator->x1 = points[0].x;
|
||||
calculator->y1 = points[0].y;
|
||||
calculator->x2 = points[0].x;
|
||||
calculator->y2 = points[0].y;
|
||||
calculator->length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i = 0; i < npoints; ++i) {
|
||||
calculator->x1 = plutovg_min(calculator->x1, points[i].x);
|
||||
calculator->y1 = plutovg_min(calculator->y1, points[i].y);
|
||||
calculator->x2 = plutovg_max(calculator->x2, points[i].x);
|
||||
calculator->y2 = plutovg_max(calculator->y2, points[i].y);
|
||||
if(command != PLUTOVG_PATH_COMMAND_MOVE_TO)
|
||||
calculator->length += hypotf(points[i].x - calculator->current_point.x, points[i].y - calculator->current_point.y);
|
||||
calculator->current_point = points[i];
|
||||
}
|
||||
}
|
||||
|
||||
float plutovg_path_extents(const plutovg_path_t* path, plutovg_rect_t* extents, bool tight)
|
||||
{
|
||||
extents_calculator_t calculator = {{0, 0}, true, 0, 0, 0, 0, 0};
|
||||
if(tight) {
|
||||
plutovg_path_traverse_flatten(path, extents_traverse_func, &calculator);
|
||||
} else {
|
||||
plutovg_path_traverse(path, extents_traverse_func, &calculator);
|
||||
}
|
||||
|
||||
if(extents) {
|
||||
extents->x = calculator.x1;
|
||||
extents->y = calculator.y1;
|
||||
extents->w = calculator.x2 - calculator.x1;
|
||||
extents->h = calculator.y2 - calculator.y1;
|
||||
}
|
||||
|
||||
return calculator.length;
|
||||
}
|
||||
|
||||
float plutovg_path_length(const plutovg_path_t* path)
|
||||
{
|
||||
return plutovg_path_extents(path, NULL, true);
|
||||
}
|
||||
|
||||
static inline bool parse_arc_flag(const char** begin, const char* end, bool* flag)
|
||||
{
|
||||
if(plutovg_skip_delim(begin, end, '0'))
|
||||
*flag = 0;
|
||||
else if(plutovg_skip_delim(begin, end, '1'))
|
||||
*flag = 1;
|
||||
else
|
||||
return false;
|
||||
plutovg_skip_ws_or_comma(begin, end, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool parse_path_coordinates(const char** begin, const char* end, float values[6], int offset, int count)
|
||||
{
|
||||
for(int i = 0; i < count; i++) {
|
||||
if(!plutovg_parse_number(begin, end, values + offset + i))
|
||||
return false;
|
||||
plutovg_skip_ws_or_comma(begin, end, NULL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool plutovg_path_parse(plutovg_path_t* path, const char* data, int length)
|
||||
{
|
||||
if(length == -1)
|
||||
length = strlen(data);
|
||||
const char* it = data;
|
||||
const char* end = it + length;
|
||||
|
||||
float values[6];
|
||||
bool flags[2];
|
||||
|
||||
float start_x = 0;
|
||||
float start_y = 0;
|
||||
float current_x = 0;
|
||||
float current_y = 0;
|
||||
float last_control_x = 0;
|
||||
float last_control_y = 0;
|
||||
|
||||
char command = 0;
|
||||
char last_command = 0;
|
||||
plutovg_skip_ws(&it, end);
|
||||
while(it < end) {
|
||||
if(PLUTOVG_IS_ALPHA(*it)) {
|
||||
command = *it++;
|
||||
plutovg_skip_ws(&it, end);
|
||||
}
|
||||
|
||||
if(!last_command && !(command == 'M' || command == 'm'))
|
||||
return false;
|
||||
if(command == 'M' || command == 'm') {
|
||||
if(!parse_path_coordinates(&it, end, values, 0, 2))
|
||||
return false;
|
||||
if(command == 'm') {
|
||||
values[0] += current_x;
|
||||
values[1] += current_y;
|
||||
}
|
||||
|
||||
plutovg_path_move_to(path, values[0], values[1]);
|
||||
current_x = start_x = values[0];
|
||||
current_y = start_y = values[1];
|
||||
command = command == 'm' ? 'l' : 'L';
|
||||
} else if(command == 'L' || command == 'l') {
|
||||
if(!parse_path_coordinates(&it, end, values, 0, 2))
|
||||
return false;
|
||||
if(command == 'l') {
|
||||
values[0] += current_x;
|
||||
values[1] += current_y;
|
||||
}
|
||||
|
||||
plutovg_path_line_to(path, values[0], values[1]);
|
||||
current_x = values[0];
|
||||
current_y = values[1];
|
||||
} else if(command == 'H' || command == 'h') {
|
||||
if(!parse_path_coordinates(&it, end, values, 0, 1))
|
||||
return false;
|
||||
if(command == 'h') {
|
||||
values[0] += current_x;
|
||||
}
|
||||
|
||||
plutovg_path_line_to(path, values[0], current_y);
|
||||
current_x = values[0];
|
||||
} else if(command == 'V' || command == 'v') {
|
||||
if(!parse_path_coordinates(&it, end, values, 1, 1))
|
||||
return false;
|
||||
if(command == 'v') {
|
||||
values[1] += current_y;
|
||||
}
|
||||
|
||||
plutovg_path_line_to(path, current_x, values[1]);
|
||||
current_y = values[1];
|
||||
} else if(command == 'Q' || command == 'q') {
|
||||
if(!parse_path_coordinates(&it, end, values, 0, 4))
|
||||
return false;
|
||||
if(command == 'q') {
|
||||
values[0] += current_x;
|
||||
values[1] += current_y;
|
||||
values[2] += current_x;
|
||||
values[3] += current_y;
|
||||
}
|
||||
|
||||
plutovg_path_quad_to(path, values[0], values[1], values[2], values[3]);
|
||||
last_control_x = values[0];
|
||||
last_control_y = values[1];
|
||||
current_x = values[2];
|
||||
current_y = values[3];
|
||||
} else if(command == 'C' || command == 'c') {
|
||||
if(!parse_path_coordinates(&it, end, values, 0, 6))
|
||||
return false;
|
||||
if(command == 'c') {
|
||||
values[0] += current_x;
|
||||
values[1] += current_y;
|
||||
values[2] += current_x;
|
||||
values[3] += current_y;
|
||||
values[4] += current_x;
|
||||
values[5] += current_y;
|
||||
}
|
||||
|
||||
plutovg_path_cubic_to(path, values[0], values[1], values[2], values[3], values[4], values[5]);
|
||||
last_control_x = values[2];
|
||||
last_control_y = values[3];
|
||||
current_x = values[4];
|
||||
current_y = values[5];
|
||||
} else if(command == 'T' || command == 't') {
|
||||
if(last_command != 'Q' && last_command != 'q' && last_command != 'T' && last_command != 't') {
|
||||
values[0] = current_x;
|
||||
values[1] = current_y;
|
||||
} else {
|
||||
values[0] = 2 * current_x - last_control_x;
|
||||
values[1] = 2 * current_y - last_control_y;
|
||||
}
|
||||
|
||||
if(!parse_path_coordinates(&it, end, values, 2, 2))
|
||||
return false;
|
||||
if(command == 't') {
|
||||
values[2] += current_x;
|
||||
values[3] += current_y;
|
||||
}
|
||||
|
||||
plutovg_path_quad_to(path, values[0], values[1], values[2], values[3]);
|
||||
last_control_x = values[0];
|
||||
last_control_y = values[1];
|
||||
current_x = values[2];
|
||||
current_y = values[3];
|
||||
} else if(command == 'S' || command == 's') {
|
||||
if(last_command != 'C' && last_command != 'c' && last_command != 'S' && last_command != 's') {
|
||||
values[0] = current_x;
|
||||
values[1] = current_y;
|
||||
} else {
|
||||
values[0] = 2 * current_x - last_control_x;
|
||||
values[1] = 2 * current_y - last_control_y;
|
||||
}
|
||||
|
||||
if(!parse_path_coordinates(&it, end, values, 2, 4))
|
||||
return false;
|
||||
if(command == 's') {
|
||||
values[2] += current_x;
|
||||
values[3] += current_y;
|
||||
values[4] += current_x;
|
||||
values[5] += current_y;
|
||||
}
|
||||
|
||||
plutovg_path_cubic_to(path, values[0], values[1], values[2], values[3], values[4], values[5]);
|
||||
last_control_x = values[2];
|
||||
last_control_y = values[3];
|
||||
current_x = values[4];
|
||||
current_y = values[5];
|
||||
} else if(command == 'A' || command == 'a') {
|
||||
if(!parse_path_coordinates(&it, end, values, 0, 3)
|
||||
|| !parse_arc_flag(&it, end, &flags[0])
|
||||
|| !parse_arc_flag(&it, end, &flags[1])
|
||||
|| !parse_path_coordinates(&it, end, values, 3, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(command == 'a') {
|
||||
values[3] += current_x;
|
||||
values[4] += current_y;
|
||||
}
|
||||
|
||||
plutovg_path_arc_to(path, values[0], values[1], PLUTOVG_DEG2RAD(values[2]), flags[0], flags[1], values[3], values[4]);
|
||||
current_x = values[3];
|
||||
current_y = values[4];
|
||||
} else if(command == 'Z' || command == 'z') {
|
||||
if(last_command == 'Z' || last_command == 'z')
|
||||
return false;
|
||||
plutovg_path_close(path);
|
||||
current_x = start_x;
|
||||
current_y = start_y;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
last_command = command;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
145
3rdparty/plutosvg/plutovg/source/plutovg-private.h
vendored
Normal file
145
3rdparty/plutosvg/plutovg/source/plutovg-private.h
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
#ifndef PLUTOVG_PRIVATE_H
|
||||
#define PLUTOVG_PRIVATE_H
|
||||
|
||||
#include "plutovg.h"
|
||||
|
||||
struct plutovg_surface {
|
||||
int ref_count;
|
||||
int width;
|
||||
int height;
|
||||
int stride;
|
||||
unsigned char* data;
|
||||
};
|
||||
|
||||
struct plutovg_path {
|
||||
int ref_count;
|
||||
int num_points;
|
||||
int num_contours;
|
||||
int num_curves;
|
||||
plutovg_point_t start_point;
|
||||
struct {
|
||||
plutovg_path_element_t* data;
|
||||
int size;
|
||||
int capacity;
|
||||
} elements;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
PLUTOVG_PAINT_TYPE_COLOR,
|
||||
PLUTOVG_PAINT_TYPE_GRADIENT,
|
||||
PLUTOVG_PAINT_TYPE_TEXTURE
|
||||
} plutovg_paint_type_t;
|
||||
|
||||
struct plutovg_paint {
|
||||
int ref_count;
|
||||
plutovg_paint_type_t type;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
plutovg_paint_t base;
|
||||
plutovg_color_t color;
|
||||
} plutovg_solid_paint_t;
|
||||
|
||||
typedef enum {
|
||||
PLUTOVG_GRADIENT_TYPE_LINEAR,
|
||||
PLUTOVG_GRADIENT_TYPE_RADIAL
|
||||
} plutovg_gradient_type_t;
|
||||
|
||||
typedef struct {
|
||||
plutovg_paint_t base;
|
||||
plutovg_gradient_type_t type;
|
||||
plutovg_spread_method_t spread;
|
||||
plutovg_matrix_t matrix;
|
||||
plutovg_gradient_stop_t* stops;
|
||||
int nstops;
|
||||
float values[6];
|
||||
} plutovg_gradient_paint_t;
|
||||
|
||||
typedef struct {
|
||||
plutovg_paint_t base;
|
||||
plutovg_texture_type_t type;
|
||||
float opacity;
|
||||
plutovg_matrix_t matrix;
|
||||
plutovg_surface_t* surface;
|
||||
} plutovg_texture_paint_t;
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int len;
|
||||
int y;
|
||||
unsigned char coverage;
|
||||
} plutovg_span_t;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
plutovg_span_t* data;
|
||||
int size;
|
||||
int capacity;
|
||||
} spans;
|
||||
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
} plutovg_span_buffer_t;
|
||||
|
||||
typedef struct {
|
||||
float offset;
|
||||
struct {
|
||||
float* data;
|
||||
int size;
|
||||
int capacity;
|
||||
} array;
|
||||
} plutovg_stroke_dash_t;
|
||||
|
||||
typedef struct {
|
||||
float width;
|
||||
plutovg_line_cap_t cap;
|
||||
plutovg_line_join_t join;
|
||||
float miter_limit;
|
||||
} plutovg_stroke_style_t;
|
||||
|
||||
typedef struct {
|
||||
plutovg_stroke_style_t style;
|
||||
plutovg_stroke_dash_t dash;
|
||||
} plutovg_stroke_data_t;
|
||||
|
||||
typedef struct plutovg_state {
|
||||
plutovg_paint_t* paint;
|
||||
plutovg_font_face_t* font_face;
|
||||
plutovg_color_t color;
|
||||
plutovg_matrix_t matrix;
|
||||
plutovg_stroke_data_t stroke;
|
||||
plutovg_span_buffer_t clip_spans;
|
||||
plutovg_fill_rule_t winding;
|
||||
plutovg_operator_t op;
|
||||
float font_size;
|
||||
float opacity;
|
||||
bool clipping;
|
||||
struct plutovg_state* next;
|
||||
} plutovg_state_t;
|
||||
|
||||
struct plutovg_canvas {
|
||||
int ref_count;
|
||||
plutovg_surface_t* surface;
|
||||
plutovg_path_t* path;
|
||||
plutovg_state_t* state;
|
||||
plutovg_state_t* freed_state;
|
||||
plutovg_rect_t clip_rect;
|
||||
plutovg_span_buffer_t clip_spans;
|
||||
plutovg_span_buffer_t fill_spans;
|
||||
};
|
||||
|
||||
void plutovg_span_buffer_init(plutovg_span_buffer_t* span_buffer);
|
||||
void plutovg_span_buffer_init_rect(plutovg_span_buffer_t* span_buffer, int x, int y, int width, int height);
|
||||
void plutovg_span_buffer_reset(plutovg_span_buffer_t* span_buffer);
|
||||
void plutovg_span_buffer_destroy(plutovg_span_buffer_t* span_buffer);
|
||||
void plutovg_span_buffer_copy(plutovg_span_buffer_t* span_buffer, const plutovg_span_buffer_t* source);
|
||||
void plutovg_span_buffer_extents(plutovg_span_buffer_t* span_buffer, plutovg_rect_t* extents);
|
||||
void plutovg_span_buffer_intersect(plutovg_span_buffer_t* span_buffer, const plutovg_span_buffer_t* a, const plutovg_span_buffer_t* b);
|
||||
|
||||
void plutovg_rasterize(plutovg_span_buffer_t* span_buffer, const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_rect_t* clip_rect, const plutovg_stroke_data_t* stroke_data, plutovg_fill_rule_t winding);
|
||||
void plutovg_blend(plutovg_canvas_t* canvas, const plutovg_span_buffer_t* span_buffer);
|
||||
void plutovg_memfill32(unsigned int* dest, int length, unsigned int value);
|
||||
|
||||
#endif // PLUTOVG_PRIVATE_H
|
||||
377
3rdparty/plutosvg/plutovg/source/plutovg-rasterize.c
vendored
Normal file
377
3rdparty/plutosvg/plutovg/source/plutovg-rasterize.c
vendored
Normal file
@@ -0,0 +1,377 @@
|
||||
#include "plutovg-private.h"
|
||||
#include "plutovg-utils.h"
|
||||
|
||||
#include "plutovg-ft-raster.h"
|
||||
#include "plutovg-ft-stroker.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
void plutovg_span_buffer_init(plutovg_span_buffer_t* span_buffer)
|
||||
{
|
||||
plutovg_array_init(span_buffer->spans);
|
||||
plutovg_span_buffer_reset(span_buffer);
|
||||
}
|
||||
|
||||
void plutovg_span_buffer_init_rect(plutovg_span_buffer_t* span_buffer, int x, int y, int width, int height)
|
||||
{
|
||||
plutovg_array_clear(span_buffer->spans);
|
||||
plutovg_array_ensure(span_buffer->spans, height);
|
||||
plutovg_span_t* spans = span_buffer->spans.data;
|
||||
for(int i = 0; i < height; i++) {
|
||||
spans[i].x = x;
|
||||
spans[i].y = y + i;
|
||||
spans[i].len = width;
|
||||
spans[i].coverage = 255;
|
||||
}
|
||||
|
||||
span_buffer->x = x;
|
||||
span_buffer->y = y;
|
||||
span_buffer->w = width;
|
||||
span_buffer->h = height;
|
||||
span_buffer->spans.size = height;
|
||||
}
|
||||
|
||||
void plutovg_span_buffer_reset(plutovg_span_buffer_t* span_buffer)
|
||||
{
|
||||
plutovg_array_clear(span_buffer->spans);
|
||||
span_buffer->x = 0;
|
||||
span_buffer->y = 0;
|
||||
span_buffer->w = -1;
|
||||
span_buffer->h = -1;
|
||||
}
|
||||
|
||||
void plutovg_span_buffer_destroy(plutovg_span_buffer_t* span_buffer)
|
||||
{
|
||||
plutovg_array_destroy(span_buffer->spans);
|
||||
}
|
||||
|
||||
void plutovg_span_buffer_copy(plutovg_span_buffer_t* span_buffer, const plutovg_span_buffer_t* source)
|
||||
{
|
||||
plutovg_array_clear(span_buffer->spans);
|
||||
plutovg_array_append(span_buffer->spans, source->spans);
|
||||
span_buffer->x = source->x;
|
||||
span_buffer->y = source->y;
|
||||
span_buffer->w = source->w;
|
||||
span_buffer->h = source->h;
|
||||
}
|
||||
|
||||
static void plutovg_span_buffer_update_extents(plutovg_span_buffer_t* span_buffer)
|
||||
{
|
||||
if(span_buffer->w != -1 && span_buffer->h != -1)
|
||||
return;
|
||||
if(span_buffer->spans.size == 0) {
|
||||
span_buffer->x = 0;
|
||||
span_buffer->y = 0;
|
||||
span_buffer->w = 0;
|
||||
span_buffer->h = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
plutovg_span_t* spans = span_buffer->spans.data;
|
||||
int x1 = INT_MAX;
|
||||
int y1 = spans[0].y;
|
||||
int x2 = 0;
|
||||
int y2 = spans[span_buffer->spans.size - 1].y;
|
||||
for(int i = 0; i < span_buffer->spans.size; i++) {
|
||||
if(spans[i].x < x1) x1 = spans[i].x;
|
||||
if(spans[i].x + spans[i].len > x2) x2 = spans[i].x + spans[i].len;
|
||||
}
|
||||
|
||||
span_buffer->x = x1;
|
||||
span_buffer->y = y1;
|
||||
span_buffer->w = x2 - x1;
|
||||
span_buffer->h = y2 - y1 + 1;
|
||||
}
|
||||
|
||||
void plutovg_span_buffer_extents(plutovg_span_buffer_t* span_buffer, plutovg_rect_t* extents)
|
||||
{
|
||||
plutovg_span_buffer_update_extents(span_buffer);
|
||||
extents->x = span_buffer->x;
|
||||
extents->y = span_buffer->y;
|
||||
extents->w = span_buffer->w;
|
||||
extents->h = span_buffer->h;
|
||||
}
|
||||
|
||||
void plutovg_span_buffer_intersect(plutovg_span_buffer_t* span_buffer, const plutovg_span_buffer_t* a, const plutovg_span_buffer_t* b)
|
||||
{
|
||||
plutovg_span_buffer_reset(span_buffer);
|
||||
plutovg_array_ensure(span_buffer->spans, plutovg_max(a->spans.size, b->spans.size));
|
||||
|
||||
plutovg_span_t* a_spans = a->spans.data;
|
||||
plutovg_span_t* a_end = a_spans + a->spans.size;
|
||||
|
||||
plutovg_span_t* b_spans = b->spans.data;
|
||||
plutovg_span_t* b_end = b_spans + b->spans.size;
|
||||
while(a_spans < a_end && b_spans < b_end) {
|
||||
if(b_spans->y > a_spans->y) {
|
||||
++a_spans;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(a_spans->y != b_spans->y) {
|
||||
++b_spans;
|
||||
continue;
|
||||
}
|
||||
|
||||
int ax1 = a_spans->x;
|
||||
int ax2 = ax1 + a_spans->len;
|
||||
int bx1 = b_spans->x;
|
||||
int bx2 = bx1 + b_spans->len;
|
||||
if(bx1 < ax1 && bx2 < ax1) {
|
||||
++b_spans;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ax1 < bx1 && ax2 < bx1) {
|
||||
++a_spans;
|
||||
continue;
|
||||
}
|
||||
|
||||
int x = plutovg_max(ax1, bx1);
|
||||
int len = plutovg_min(ax2, bx2) - x;
|
||||
if(len) {
|
||||
plutovg_array_ensure(span_buffer->spans, 1);
|
||||
plutovg_span_t* span = span_buffer->spans.data + span_buffer->spans.size;
|
||||
span->x = x;
|
||||
span->len = len;
|
||||
span->y = a_spans->y;
|
||||
span->coverage = (a_spans->coverage * b_spans->coverage) / 255;
|
||||
span_buffer->spans.size += 1;
|
||||
}
|
||||
|
||||
if(ax2 < bx2) {
|
||||
++a_spans;
|
||||
} else {
|
||||
++b_spans;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define ALIGN_SIZE(size) (((size) + 7ul) & ~7ul)
|
||||
static PVG_FT_Outline* ft_outline_create(int points, int contours)
|
||||
{
|
||||
size_t points_size = ALIGN_SIZE((points + contours) * sizeof(PVG_FT_Vector));
|
||||
size_t tags_size = ALIGN_SIZE((points + contours) * sizeof(char));
|
||||
size_t contours_size = ALIGN_SIZE(contours * sizeof(int));
|
||||
size_t contours_flag_size = ALIGN_SIZE(contours * sizeof(char));
|
||||
PVG_FT_Outline* outline = malloc(points_size + tags_size + contours_size + contours_flag_size + sizeof(PVG_FT_Outline));
|
||||
|
||||
PVG_FT_Byte* outline_data = (PVG_FT_Byte*)(outline + 1);
|
||||
outline->points = (PVG_FT_Vector*)(outline_data);
|
||||
outline->tags = (char*)(outline_data + points_size);
|
||||
outline->contours = (int*)(outline_data + points_size + tags_size);
|
||||
outline->contours_flag = (char*)(outline_data + points_size + tags_size + contours_size);
|
||||
outline->n_points = 0;
|
||||
outline->n_contours = 0;
|
||||
outline->flags = 0x0;
|
||||
return outline;
|
||||
}
|
||||
|
||||
static void ft_outline_destroy(PVG_FT_Outline* outline)
|
||||
{
|
||||
free(outline);
|
||||
}
|
||||
|
||||
#define FT_COORD(x) (PVG_FT_Pos)((x) * 64)
|
||||
static void ft_outline_move_to(PVG_FT_Outline* ft, float x, float y)
|
||||
{
|
||||
ft->points[ft->n_points].x = FT_COORD(x);
|
||||
ft->points[ft->n_points].y = FT_COORD(y);
|
||||
ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON;
|
||||
if(ft->n_points) {
|
||||
ft->contours[ft->n_contours] = ft->n_points - 1;
|
||||
ft->n_contours++;
|
||||
}
|
||||
|
||||
ft->contours_flag[ft->n_contours] = 1;
|
||||
ft->n_points++;
|
||||
}
|
||||
|
||||
static void ft_outline_line_to(PVG_FT_Outline* ft, float x, float y)
|
||||
{
|
||||
ft->points[ft->n_points].x = FT_COORD(x);
|
||||
ft->points[ft->n_points].y = FT_COORD(y);
|
||||
ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON;
|
||||
ft->n_points++;
|
||||
}
|
||||
|
||||
static void ft_outline_cubic_to(PVG_FT_Outline* ft, float x1, float y1, float x2, float y2, float x3, float y3)
|
||||
{
|
||||
ft->points[ft->n_points].x = FT_COORD(x1);
|
||||
ft->points[ft->n_points].y = FT_COORD(y1);
|
||||
ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_CUBIC;
|
||||
ft->n_points++;
|
||||
|
||||
ft->points[ft->n_points].x = FT_COORD(x2);
|
||||
ft->points[ft->n_points].y = FT_COORD(y2);
|
||||
ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_CUBIC;
|
||||
ft->n_points++;
|
||||
|
||||
ft->points[ft->n_points].x = FT_COORD(x3);
|
||||
ft->points[ft->n_points].y = FT_COORD(y3);
|
||||
ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON;
|
||||
ft->n_points++;
|
||||
}
|
||||
|
||||
static void ft_outline_close(PVG_FT_Outline* ft)
|
||||
{
|
||||
ft->contours_flag[ft->n_contours] = 0;
|
||||
int index = ft->n_contours ? ft->contours[ft->n_contours - 1] + 1 : 0;
|
||||
if(index == ft->n_points)
|
||||
return;
|
||||
ft->points[ft->n_points].x = ft->points[index].x;
|
||||
ft->points[ft->n_points].y = ft->points[index].y;
|
||||
ft->tags[ft->n_points] = PVG_FT_CURVE_TAG_ON;
|
||||
ft->n_points++;
|
||||
}
|
||||
|
||||
static void ft_outline_end(PVG_FT_Outline* ft)
|
||||
{
|
||||
if(ft->n_points) {
|
||||
ft->contours[ft->n_contours] = ft->n_points - 1;
|
||||
ft->n_contours++;
|
||||
}
|
||||
}
|
||||
|
||||
static PVG_FT_Outline* ft_outline_convert_stroke(const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_stroke_data_t* stroke_data);
|
||||
|
||||
static PVG_FT_Outline* ft_outline_convert(const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_stroke_data_t* stroke_data)
|
||||
{
|
||||
if(stroke_data) {
|
||||
return ft_outline_convert_stroke(path, matrix, stroke_data);
|
||||
}
|
||||
|
||||
plutovg_path_iterator_t it;
|
||||
plutovg_path_iterator_init(&it, path);
|
||||
|
||||
plutovg_point_t points[3];
|
||||
PVG_FT_Outline* outline = ft_outline_create(path->num_points, path->num_contours);
|
||||
while(plutovg_path_iterator_has_next(&it)) {
|
||||
switch(plutovg_path_iterator_next(&it, points)) {
|
||||
case PLUTOVG_PATH_COMMAND_MOVE_TO:
|
||||
plutovg_matrix_map_points(matrix, points, points, 1);
|
||||
ft_outline_move_to(outline, points[0].x, points[0].y);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_LINE_TO:
|
||||
plutovg_matrix_map_points(matrix, points, points, 1);
|
||||
ft_outline_line_to(outline, points[0].x, points[0].y);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CUBIC_TO:
|
||||
plutovg_matrix_map_points(matrix, points, points, 3);
|
||||
ft_outline_cubic_to(outline, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y);
|
||||
break;
|
||||
case PLUTOVG_PATH_COMMAND_CLOSE:
|
||||
ft_outline_close(outline);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ft_outline_end(outline);
|
||||
return outline;
|
||||
}
|
||||
|
||||
static PVG_FT_Outline* ft_outline_convert_dash(const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_stroke_dash_t* stroke_dash)
|
||||
{
|
||||
if(stroke_dash->array.size == 0)
|
||||
return ft_outline_convert(path, matrix, NULL);
|
||||
plutovg_path_t* dashed = plutovg_path_clone_dashed(path, stroke_dash->offset, stroke_dash->array.data, stroke_dash->array.size);
|
||||
PVG_FT_Outline* outline = ft_outline_convert(dashed, matrix, NULL);
|
||||
plutovg_path_destroy(dashed);
|
||||
return outline;
|
||||
}
|
||||
|
||||
static PVG_FT_Outline* ft_outline_convert_stroke(const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_stroke_data_t* stroke_data)
|
||||
{
|
||||
double scale_x = sqrt(matrix->a * matrix->a + matrix->b * matrix->b);
|
||||
double scale_y = sqrt(matrix->c * matrix->c + matrix->d * matrix->d);
|
||||
|
||||
double scale = hypot(scale_x, scale_y) / PLUTOVG_SQRT2;
|
||||
double width = stroke_data->style.width * scale;
|
||||
|
||||
PVG_FT_Fixed ftWidth = (PVG_FT_Fixed)(width * 0.5 * (1 << 6));
|
||||
PVG_FT_Fixed ftMiterLimit = (PVG_FT_Fixed)(stroke_data->style.miter_limit * (1 << 16));
|
||||
|
||||
PVG_FT_Stroker_LineCap ftCap;
|
||||
switch(stroke_data->style.cap) {
|
||||
case PLUTOVG_LINE_CAP_SQUARE:
|
||||
ftCap = PVG_FT_STROKER_LINECAP_SQUARE;
|
||||
break;
|
||||
case PLUTOVG_LINE_CAP_ROUND:
|
||||
ftCap = PVG_FT_STROKER_LINECAP_ROUND;
|
||||
break;
|
||||
default:
|
||||
ftCap = PVG_FT_STROKER_LINECAP_BUTT;
|
||||
break;
|
||||
}
|
||||
|
||||
PVG_FT_Stroker_LineJoin ftJoin;
|
||||
switch(stroke_data->style.join) {
|
||||
case PLUTOVG_LINE_JOIN_BEVEL:
|
||||
ftJoin = PVG_FT_STROKER_LINEJOIN_BEVEL;
|
||||
break;
|
||||
case PLUTOVG_LINE_JOIN_ROUND:
|
||||
ftJoin = PVG_FT_STROKER_LINEJOIN_ROUND;
|
||||
break;
|
||||
default:
|
||||
ftJoin = PVG_FT_STROKER_LINEJOIN_MITER_FIXED;
|
||||
break;
|
||||
}
|
||||
|
||||
PVG_FT_Stroker stroker;
|
||||
PVG_FT_Stroker_New(&stroker);
|
||||
PVG_FT_Stroker_Set(stroker, ftWidth, ftCap, ftJoin, ftMiterLimit);
|
||||
|
||||
PVG_FT_Outline* outline = ft_outline_convert_dash(path, matrix, &stroke_data->dash);
|
||||
PVG_FT_Stroker_ParseOutline(stroker, outline);
|
||||
|
||||
PVG_FT_UInt points;
|
||||
PVG_FT_UInt contours;
|
||||
PVG_FT_Stroker_GetCounts(stroker, &points, &contours);
|
||||
|
||||
PVG_FT_Outline* stroke_outline = ft_outline_create(points, contours);
|
||||
PVG_FT_Stroker_Export(stroker, stroke_outline);
|
||||
|
||||
PVG_FT_Stroker_Done(stroker);
|
||||
ft_outline_destroy(outline);
|
||||
return stroke_outline;
|
||||
}
|
||||
|
||||
static void spans_generation_callback(int count, const PVG_FT_Span* spans, void* user)
|
||||
{
|
||||
plutovg_span_buffer_t* span_buffer = (plutovg_span_buffer_t*)(user);
|
||||
plutovg_array_append_data(span_buffer->spans, spans, count);
|
||||
}
|
||||
|
||||
void plutovg_rasterize(plutovg_span_buffer_t* span_buffer, const plutovg_path_t* path, const plutovg_matrix_t* matrix, const plutovg_rect_t* clip_rect, const plutovg_stroke_data_t* stroke_data, plutovg_fill_rule_t winding)
|
||||
{
|
||||
PVG_FT_Outline* outline = ft_outline_convert(path, matrix, stroke_data);
|
||||
if(stroke_data) {
|
||||
outline->flags = PVG_FT_OUTLINE_NONE;
|
||||
} else {
|
||||
switch(winding) {
|
||||
case PLUTOVG_FILL_RULE_EVEN_ODD:
|
||||
outline->flags = PVG_FT_OUTLINE_EVEN_ODD_FILL;
|
||||
break;
|
||||
default:
|
||||
outline->flags = PVG_FT_OUTLINE_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PVG_FT_Raster_Params params;
|
||||
params.flags = PVG_FT_RASTER_FLAG_DIRECT | PVG_FT_RASTER_FLAG_AA;
|
||||
params.gray_spans = spans_generation_callback;
|
||||
params.user = span_buffer;
|
||||
params.source = outline;
|
||||
if(clip_rect) {
|
||||
params.flags |= PVG_FT_RASTER_FLAG_CLIP;
|
||||
params.clip_box.xMin = (PVG_FT_Pos)clip_rect->x;
|
||||
params.clip_box.yMin = (PVG_FT_Pos)clip_rect->y;
|
||||
params.clip_box.xMax = (PVG_FT_Pos)(clip_rect->x + clip_rect->w);
|
||||
params.clip_box.yMax = (PVG_FT_Pos)(clip_rect->y + clip_rect->h);
|
||||
}
|
||||
|
||||
plutovg_span_buffer_reset(span_buffer);
|
||||
PVG_FT_Raster_Render(¶ms);
|
||||
ft_outline_destroy(outline);
|
||||
}
|
||||
1724
3rdparty/plutosvg/plutovg/source/plutovg-stb-image-write.h
vendored
Normal file
1724
3rdparty/plutosvg/plutovg/source/plutovg-stb-image-write.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7988
3rdparty/plutosvg/plutovg/source/plutovg-stb-image.h
vendored
Normal file
7988
3rdparty/plutosvg/plutovg/source/plutovg-stb-image.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5077
3rdparty/plutosvg/plutovg/source/plutovg-stb-truetype.h
vendored
Normal file
5077
3rdparty/plutosvg/plutovg/source/plutovg-stb-truetype.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
300
3rdparty/plutosvg/plutovg/source/plutovg-surface.c
vendored
Normal file
300
3rdparty/plutosvg/plutovg/source/plutovg-surface.c
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
#include "plutovg-private.h"
|
||||
#include "plutovg-utils.h"
|
||||
|
||||
#define STB_IMAGE_WRITE_STATIC
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "plutovg-stb-image-write.h"
|
||||
|
||||
#define STB_IMAGE_STATIC
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "plutovg-stb-image.h"
|
||||
|
||||
static plutovg_surface_t* plutovg_surface_create_uninitialized(int width, int height)
|
||||
{
|
||||
if(width > STBI_MAX_DIMENSIONS || height > STBI_MAX_DIMENSIONS)
|
||||
return NULL;
|
||||
const size_t size = width * height * 4;
|
||||
plutovg_surface_t* surface = malloc(size + sizeof(plutovg_surface_t));
|
||||
if(surface == NULL)
|
||||
return NULL;
|
||||
surface->ref_count = 1;
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->stride = width * 4;
|
||||
surface->data = (uint8_t*)(surface + 1);
|
||||
return surface;
|
||||
}
|
||||
|
||||
plutovg_surface_t* plutovg_surface_create(int width, int height)
|
||||
{
|
||||
plutovg_surface_t* surface = plutovg_surface_create_uninitialized(width, height);
|
||||
if(surface)
|
||||
memset(surface->data, 0, surface->height * surface->stride);
|
||||
return surface;
|
||||
}
|
||||
|
||||
plutovg_surface_t* plutovg_surface_create_for_data(unsigned char* data, int width, int height, int stride)
|
||||
{
|
||||
plutovg_surface_t* surface = malloc(sizeof(plutovg_surface_t));
|
||||
surface->ref_count = 1;
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->stride = stride;
|
||||
surface->data = data;
|
||||
return surface;
|
||||
}
|
||||
|
||||
static plutovg_surface_t* plutovg_surface_load_from_image(stbi_uc* image, int width, int height)
|
||||
{
|
||||
plutovg_surface_t* surface = plutovg_surface_create_uninitialized(width, height);
|
||||
if(surface)
|
||||
plutovg_convert_rgba_to_argb(surface->data, image, surface->width, surface->height, surface->stride);
|
||||
stbi_image_free(image);
|
||||
return surface;
|
||||
}
|
||||
|
||||
plutovg_surface_t* plutovg_surface_load_from_image_file(const char* filename)
|
||||
{
|
||||
int width, height, channels;
|
||||
stbi_uc* image = stbi_load(filename, &width, &height, &channels, STBI_rgb_alpha);
|
||||
if(image == NULL)
|
||||
return NULL;
|
||||
return plutovg_surface_load_from_image(image, width, height);
|
||||
}
|
||||
|
||||
plutovg_surface_t* plutovg_surface_load_from_image_data(const void* data, int length)
|
||||
{
|
||||
int width, height, channels;
|
||||
stbi_uc* image = stbi_load_from_memory(data, length, &width, &height, &channels, STBI_rgb_alpha);
|
||||
if(image == NULL)
|
||||
return NULL;
|
||||
return plutovg_surface_load_from_image(image, width, height);
|
||||
}
|
||||
|
||||
static const uint8_t base64_table[128] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3F,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
|
||||
0x3C, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
|
||||
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
|
||||
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
|
||||
0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
plutovg_surface_t* plutovg_surface_load_from_image_base64(const char* data, int length)
|
||||
{
|
||||
plutovg_surface_t* surface = NULL;
|
||||
uint8_t* output_data = NULL;
|
||||
size_t output_length = 0;
|
||||
|
||||
size_t equals_sign_count = 0;
|
||||
size_t sidx = 0;
|
||||
size_t didx = 0;
|
||||
|
||||
if(length == -1)
|
||||
length = strlen(data);
|
||||
output_data = malloc(length);
|
||||
if(output_data == NULL)
|
||||
return NULL;
|
||||
for(int i = 0; i < length; ++i) {
|
||||
uint8_t cc = data[i];
|
||||
if(cc == '=') {
|
||||
++equals_sign_count;
|
||||
} else if(cc == '+' || cc == '/' || PLUTOVG_IS_ALNUM(cc)) {
|
||||
if(equals_sign_count > 0)
|
||||
goto cleanup;
|
||||
output_data[output_length++] = base64_table[cc];
|
||||
} else if(!PLUTOVG_IS_WS(cc)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if(output_length == 0 || equals_sign_count > 2 || (output_length % 4) == 1)
|
||||
goto cleanup;
|
||||
output_length -= (output_length + 3) / 4;
|
||||
if(output_length == 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if(output_length > 1) {
|
||||
while(didx < output_length - 2) {
|
||||
output_data[didx + 0] = (((output_data[sidx + 0] << 2) & 255) | ((output_data[sidx + 1] >> 4) & 003));
|
||||
output_data[didx + 1] = (((output_data[sidx + 1] << 4) & 255) | ((output_data[sidx + 2] >> 2) & 017));
|
||||
output_data[didx + 2] = (((output_data[sidx + 2] << 6) & 255) | ((output_data[sidx + 3] >> 0) & 077));
|
||||
sidx += 4;
|
||||
didx += 3;
|
||||
}
|
||||
}
|
||||
|
||||
if(didx < output_length)
|
||||
output_data[didx] = (((output_data[sidx + 0] << 2) & 255) | ((output_data[sidx + 1] >> 4) & 003));
|
||||
if(++didx < output_length) {
|
||||
output_data[didx] = (((output_data[sidx + 1] << 4) & 255) | ((output_data[sidx + 2] >> 2) & 017));
|
||||
}
|
||||
|
||||
surface = plutovg_surface_load_from_image_data(output_data, output_length);
|
||||
cleanup:
|
||||
free(output_data);
|
||||
return surface;
|
||||
}
|
||||
|
||||
plutovg_surface_t* plutovg_surface_reference(plutovg_surface_t* surface)
|
||||
{
|
||||
if(surface == NULL)
|
||||
return NULL;
|
||||
++surface->ref_count;
|
||||
return surface;
|
||||
}
|
||||
|
||||
void plutovg_surface_destroy(plutovg_surface_t* surface)
|
||||
{
|
||||
if(surface == NULL)
|
||||
return;
|
||||
if(--surface->ref_count == 0) {
|
||||
free(surface);
|
||||
}
|
||||
}
|
||||
|
||||
int plutovg_surface_get_reference_count(const plutovg_surface_t* surface)
|
||||
{
|
||||
if(surface)
|
||||
return surface->ref_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char* plutovg_surface_get_data(const plutovg_surface_t* surface)
|
||||
{
|
||||
return surface->data;
|
||||
}
|
||||
|
||||
int plutovg_surface_get_width(const plutovg_surface_t* surface)
|
||||
{
|
||||
return surface->width;
|
||||
}
|
||||
|
||||
int plutovg_surface_get_height(const plutovg_surface_t* surface)
|
||||
{
|
||||
return surface->height;
|
||||
}
|
||||
|
||||
int plutovg_surface_get_stride(const plutovg_surface_t* surface)
|
||||
{
|
||||
return surface->stride;
|
||||
}
|
||||
|
||||
void plutovg_surface_clear(plutovg_surface_t* surface, const plutovg_color_t* color)
|
||||
{
|
||||
uint32_t pixel = plutovg_premultiply_argb(plutovg_color_to_argb32(color));
|
||||
for(int y = 0; y < surface->height; y++) {
|
||||
uint32_t* pixels = (uint32_t*)(surface->data + surface->stride * y);
|
||||
plutovg_memfill32(pixels, surface->width, pixel);
|
||||
}
|
||||
}
|
||||
|
||||
static void plutovg_surface_write_begin(const plutovg_surface_t* surface)
|
||||
{
|
||||
plutovg_convert_argb_to_rgba(surface->data, surface->data, surface->width, surface->height, surface->stride);
|
||||
}
|
||||
|
||||
static void plutovg_surface_write_end(const plutovg_surface_t* surface)
|
||||
{
|
||||
plutovg_convert_rgba_to_argb(surface->data, surface->data, surface->width, surface->height, surface->stride);
|
||||
}
|
||||
|
||||
bool plutovg_surface_write_to_png(const plutovg_surface_t* surface, const char* filename)
|
||||
{
|
||||
plutovg_surface_write_begin(surface);
|
||||
int success = stbi_write_png(filename, surface->width, surface->height, 4, surface->data, surface->stride);
|
||||
plutovg_surface_write_end(surface);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool plutovg_surface_write_to_jpg(const plutovg_surface_t* surface, const char* filename, int quality)
|
||||
{
|
||||
plutovg_surface_write_begin(surface);
|
||||
int success = stbi_write_jpg(filename, surface->width, surface->height, 4, surface->data, quality);
|
||||
plutovg_surface_write_end(surface);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool plutovg_surface_write_to_png_stream(const plutovg_surface_t* surface, plutovg_write_func_t write_func, void* closure)
|
||||
{
|
||||
plutovg_surface_write_begin(surface);
|
||||
int success = stbi_write_png_to_func(write_func, closure, surface->width, surface->height, 4, surface->data, surface->stride);
|
||||
plutovg_surface_write_end(surface);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool plutovg_surface_write_to_jpg_stream(const plutovg_surface_t* surface, plutovg_write_func_t write_func, void* closure, int quality)
|
||||
{
|
||||
plutovg_surface_write_begin(surface);
|
||||
int success = stbi_write_jpg_to_func(write_func, closure, surface->width, surface->height, 4, surface->data, quality);
|
||||
plutovg_surface_write_end(surface);
|
||||
return success;
|
||||
}
|
||||
|
||||
void plutovg_convert_argb_to_rgba(unsigned char* dst, const unsigned char* src, int width, int height, int stride)
|
||||
{
|
||||
for(int y = 0; y < height; y++) {
|
||||
const uint32_t* src_row = (const uint32_t*)(src + stride * y);
|
||||
unsigned char* dst_row = dst + stride * y;
|
||||
for(int x = 0; x < width; x++) {
|
||||
uint32_t pixel = src_row[x];
|
||||
uint32_t a = (pixel >> 24) & 0xFF;
|
||||
if(a == 0) {
|
||||
*dst_row++ = 0;
|
||||
*dst_row++ = 0;
|
||||
*dst_row++ = 0;
|
||||
*dst_row++ = 0;
|
||||
} else {
|
||||
uint32_t r = (pixel >> 16) & 0xFF;
|
||||
uint32_t g = (pixel >> 8) & 0xFF;
|
||||
uint32_t b = (pixel >> 0) & 0xFF;
|
||||
if(a != 255) {
|
||||
r = (r * 255) / a;
|
||||
g = (g * 255) / a;
|
||||
b = (b * 255) / a;
|
||||
}
|
||||
|
||||
*dst_row++ = r;
|
||||
*dst_row++ = g;
|
||||
*dst_row++ = b;
|
||||
*dst_row++ = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void plutovg_convert_rgba_to_argb(unsigned char* dst, const unsigned char* src, int width, int height, int stride)
|
||||
{
|
||||
for(int y = 0; y < height; y++) {
|
||||
const unsigned char* src_row = src + stride * y;
|
||||
uint32_t* dst_row = (uint32_t*)(dst + stride * y);
|
||||
for(int x = 0; x < width; x++) {
|
||||
uint32_t a = src_row[4 * x + 3];
|
||||
if(a == 0) {
|
||||
dst_row[x] = 0x00000000;
|
||||
} else {
|
||||
uint32_t r = src_row[4 * x + 0];
|
||||
uint32_t g = src_row[4 * x + 1];
|
||||
uint32_t b = src_row[4 * x + 2];
|
||||
if(a != 255) {
|
||||
r = (r * a) / 255;
|
||||
g = (g * a) / 255;
|
||||
b = (b * a) / 255;
|
||||
}
|
||||
|
||||
dst_row[x] = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
211
3rdparty/plutosvg/plutovg/source/plutovg-utils.h
vendored
Normal file
211
3rdparty/plutosvg/plutovg/source/plutovg-utils.h
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
#ifndef PLUTOVG_UTILS_H
|
||||
#define PLUTOVG_UTILS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
#define PLUTOVG_IS_NUM(c) ((c) >= '0' && (c) <= '9')
|
||||
#define PLUTOVG_IS_ALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
|
||||
#define PLUTOVG_IS_ALNUM(c) (PLUTOVG_IS_ALPHA(c) || PLUTOVG_IS_NUM(c))
|
||||
#define PLUTOVG_IS_WS(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r')
|
||||
|
||||
#define plutovg_min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define plutovg_max(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define plutovg_clamp(v, lo, hi) ((v) < (lo) ? (lo) : (hi) < (v) ? (hi) : (v))
|
||||
|
||||
#define plutovg_alpha(c) (((c) >> 24) & 0xff)
|
||||
#define plutovg_red(c) (((c) >> 16) & 0xff)
|
||||
#define plutovg_green(c) (((c) >> 8) & 0xff)
|
||||
#define plutovg_blue(c) (((c) >> 0) & 0xff)
|
||||
|
||||
#define plutovg_array_init(array) \
|
||||
do { \
|
||||
(array).data = NULL; \
|
||||
(array).size = 0; \
|
||||
(array).capacity = 0; \
|
||||
} while(0)
|
||||
|
||||
#define plutovg_array_ensure(array, count) \
|
||||
do { \
|
||||
if((array).size + (count) > (array).capacity) { \
|
||||
int capacity = (array).size + (count); \
|
||||
int newcapacity = (array).capacity == 0 ? 8 : (array).capacity; \
|
||||
while(newcapacity < capacity) { newcapacity *= 2; } \
|
||||
(array).data = realloc((array).data, newcapacity * sizeof((array).data[0])); \
|
||||
(array).capacity = newcapacity; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define plutovg_array_append_data(array, newdata, count) \
|
||||
do { \
|
||||
if(newdata && count > 0) { \
|
||||
plutovg_array_ensure(array, count); \
|
||||
memcpy((array).data + (array).size, newdata, (count) * sizeof((newdata)[0])); \
|
||||
(array).size += count; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define plutovg_array_append(array, other) plutovg_array_append_data(array, (other).data, (other).size)
|
||||
#define plutovg_array_clear(array) ((array).size = 0)
|
||||
#define plutovg_array_destroy(array) free((array).data)
|
||||
|
||||
static inline uint32_t plutovg_premultiply_argb(uint32_t color)
|
||||
{
|
||||
uint32_t a = plutovg_alpha(color);
|
||||
uint32_t r = plutovg_red(color);
|
||||
uint32_t g = plutovg_green(color);
|
||||
uint32_t b = plutovg_blue(color);
|
||||
if(a != 255) {
|
||||
r = (r * a) / 255;
|
||||
g = (g * a) / 255;
|
||||
b = (b * a) / 255;
|
||||
}
|
||||
|
||||
return (a << 24) | (r << 16) | (g << 8) | (b);
|
||||
}
|
||||
|
||||
static inline bool plutovg_parse_number(const char** begin, const char* end, float* number)
|
||||
{
|
||||
const char* it = *begin;
|
||||
float integer = 0;
|
||||
float fraction = 0;
|
||||
float exponent = 0;
|
||||
int sign = 1;
|
||||
int expsign = 1;
|
||||
|
||||
if(it < end && *it == '+') {
|
||||
++it;
|
||||
} else if(it < end && *it == '-') {
|
||||
++it;
|
||||
sign = -1;
|
||||
}
|
||||
|
||||
if(it >= end || (*it != '.' && !PLUTOVG_IS_NUM(*it)))
|
||||
return false;
|
||||
if(PLUTOVG_IS_NUM(*it)) {
|
||||
do {
|
||||
integer = 10.f * integer + (*it++ - '0');
|
||||
} while(it < end && PLUTOVG_IS_NUM(*it));
|
||||
}
|
||||
|
||||
if(it < end && *it == '.') {
|
||||
++it;
|
||||
if(it >= end || !PLUTOVG_IS_NUM(*it))
|
||||
return false;
|
||||
float divisor = 1.f;
|
||||
do {
|
||||
fraction = 10.f * fraction + (*it++ - '0');
|
||||
divisor *= 10.f;
|
||||
} while(it < end && PLUTOVG_IS_NUM(*it));
|
||||
fraction /= divisor;
|
||||
}
|
||||
|
||||
if(it < end && (*it == 'e' || *it == 'E')) {
|
||||
++it;
|
||||
if(it < end && *it == '+') {
|
||||
++it;
|
||||
} else if(it < end && *it == '-') {
|
||||
++it;
|
||||
expsign = -1;
|
||||
}
|
||||
|
||||
if(it >= end || !PLUTOVG_IS_NUM(*it))
|
||||
return false;
|
||||
do {
|
||||
exponent = 10 * exponent + (*it++ - '0');
|
||||
} while(it < end && PLUTOVG_IS_NUM(*it));
|
||||
}
|
||||
|
||||
*begin = it;
|
||||
*number = sign * (integer + fraction);
|
||||
if(exponent)
|
||||
*number *= powf(10.f, expsign * exponent);
|
||||
return *number >= -FLT_MAX && *number <= FLT_MAX;
|
||||
}
|
||||
|
||||
static inline bool plutovg_skip_delim(const char** begin, const char* end, const char delim)
|
||||
{
|
||||
const char* it = *begin;
|
||||
if(it < end && *it == delim) {
|
||||
*begin = it + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool plutovg_skip_string(const char** begin, const char* end, const char* data)
|
||||
{
|
||||
const char* it = *begin;
|
||||
while(it < end && *data && *it == *data) {
|
||||
++data;
|
||||
++it;
|
||||
}
|
||||
|
||||
if(*data == '\0') {
|
||||
*begin = it;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool plutovg_skip_ws(const char** begin, const char* end)
|
||||
{
|
||||
const char* it = *begin;
|
||||
while(it < end && PLUTOVG_IS_WS(*it))
|
||||
++it;
|
||||
*begin = it;
|
||||
return it < end;
|
||||
}
|
||||
|
||||
static inline bool plutovg_skip_ws_and_delim(const char** begin, const char* end, char delim)
|
||||
{
|
||||
const char* it = *begin;
|
||||
if(plutovg_skip_ws(&it, end)) {
|
||||
if(!plutovg_skip_delim(&it, end, delim))
|
||||
return false;
|
||||
plutovg_skip_ws(&it, end);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
*begin = it;
|
||||
return it < end;
|
||||
}
|
||||
|
||||
static inline bool plutovg_skip_ws_and_comma(const char** begin, const char* end)
|
||||
{
|
||||
return plutovg_skip_ws_and_delim(begin, end, ',');
|
||||
}
|
||||
|
||||
static inline bool plutovg_skip_ws_or_delim(const char** begin, const char* end, char delim, bool* has_delim)
|
||||
{
|
||||
const char* it = *begin;
|
||||
if(has_delim)
|
||||
*has_delim = false;
|
||||
if(plutovg_skip_ws(&it, end)) {
|
||||
if(plutovg_skip_delim(&it, end, delim)) {
|
||||
if(has_delim)
|
||||
*has_delim = true;
|
||||
plutovg_skip_ws(&it, end);
|
||||
}
|
||||
}
|
||||
|
||||
if(it == *begin)
|
||||
return false;
|
||||
*begin = it;
|
||||
return it < end;
|
||||
}
|
||||
|
||||
static inline bool plutovg_skip_ws_or_comma(const char** begin, const char* end, bool* has_comma)
|
||||
{
|
||||
return plutovg_skip_ws_or_delim(begin, end, ',', has_comma);
|
||||
}
|
||||
|
||||
#endif // PLUTOVG_UTILS_H
|
||||
Reference in New Issue
Block a user