47 int slen = strlen(
string);
57 int newsize=slen + 1 + 7 + 7*ndx + 1 + 7 + 7 + 2;
58 newsize = 8*((7 + newsize)/8);
59 char *smuggle=(
char *)malloc(newsize);
60 strcpy(smuggle,
string);
61 char *cptr = smuggle + slen + 1;
62 sprintf(cptr,
"%07d",ndx);
64 for(
int i=0; i<ndx ; i++){
65 sprintf(cptr,
" %6f",adx[i]);
70 sprintf(cptr,
" %6f",ky);
72 sprintf(cptr,
" %6d",(
int) rtl);
111 double half_leading = 0.5 * (line_height_multiplier - 1.0) * emSize();
112 ascent += half_leading;
113 descent += half_leading;
121 auto const &glyph_span = span(&layout);
128 double sin_rotation = sin(r);
129 double cos_rotation = cos(r);
130 matrix[0] = glyph_span.font_size * cos_rotation;
131 matrix[1] = glyph_span.font_size * sin_rotation;
132 matrix[2] = glyph_span.font_size * sin_rotation;
133 matrix[3] = -glyph_span.font_size * cos_rotation * vertical_scale;
138 matrix[4] = line(&layout).baseline_y + y;
139 matrix[5] = chunk(&layout).left_x + x;
142 matrix[4] = chunk(&layout).left_x + x;
143 matrix[5] = line(&layout).baseline_y + y;
153 for (
int i = 0; i <
_spans.size(); i++) {
158 if (
_spans[i].line(
this).hidden) {
163 auto style = text_source->
style;
166 style->text_decoration_data.ascender =
_spans[i].line_height.getTypoAscent();
167 style->text_decoration_data.descender =
_spans[i].line_height.getTypoDescent();
169 auto line_of_span = [
this] (
int i) {
return _chunks[
_spans[i].in_chunk].in_line; };
170 style->text_decoration_data.tspan_line_start = i == 0 || line_of_span(i) != line_of_span(i - 1);
171 style->text_decoration_data.tspan_line_end = i ==
_spans.size() - 1 || line_of_span(i) != line_of_span(i + 1);
174 double underline_thickness, underline_position, line_through_thickness, line_through_position;
175 _spans[i].font->FontDecoration(underline_position, underline_thickness, line_through_position, line_through_thickness);
176 style->text_decoration_data.underline_thickness = underline_thickness;
177 style->text_decoration_data.underline_position = underline_position;
178 style->text_decoration_data.line_through_thickness = line_through_thickness;
179 style->text_decoration_data.line_through_position = line_through_position;
181 style->text_decoration_data.underline_thickness = 0.0;
182 style->text_decoration_data.underline_position = 0.0;
183 style->text_decoration_data.line_through_thickness = 0.0;
184 style->text_decoration_data.line_through_position = 0.0;
189 if (style->filter.set) {
190 if (
auto filter = style->getFilter()) {
195 if (style->fill.isPaintserver()) {
196 if (
auto fill = style->getFillPaintServer()) {
197 style_attachments.
attachFill(drawing_text, fill, paintbox);
201 if (style->stroke.isPaintserver()) {
202 if (
auto stroke = style->getStrokePaintServer()) {
203 style_attachments.
attachStroke(drawing_text, stroke, paintbox);
207 bool first_line_glyph =
true;
211 if (first_line_glyph && style->text_decoration_data.tspan_line_start) {
212 first_line_glyph =
false;
217 drawing_text->addComponent(
_spans[i].font,
221 _spans[i].line_height.getMaxAscent(),
222 _spans[i].line_height.getMaxDescent(),
228 drawing_text->setStyle(style);
229 drawing_text->setItemBounds(paintbox);
231 parent->appendChild(drawing_text);
233 parent->setItemBounds(paintbox);
240 for (
unsigned glyph_index = 0 ; glyph_index <
_glyphs.size() ; glyph_index++) {
241 if (
_glyphs[glyph_index].hidden)
continue;
247 if ((
int)
_glyphs[glyph_index].in_character >
start + length)
continue;
253 if(
_glyphs[glyph_index].span(
this).font) {
256 auto glyph_box = *glyph_rect * total_transform;
262 if (!text_source->style->stroke.isNone()) {
264 glyph_box.expandBy(0.5 * text_source->style->stroke_width.computed *
scale);
280bool text_to_path = ctx->module->textToPath();
282float hold_dx[MAX_DX];
289 for (
unsigned glyph_index = 0 ; glyph_index <
_glyphs.size() ; glyph_index++) {
295 glyph_matrix =
_glyphs[glyph_index].transform(*
this);
298 ctx->
fill(temp_pv, ctm, text_source->
style, pbox, dbox, bbox);
300 ctx->
stroke(temp_pv, ctm, text_source->
style, pbox, dbox, bbox);
313 for (
unsigned char_index = 0 ; char_index <
_characters.size() ; ) {
314 Glib::ustring text_string;
316 int glyph_index =
_characters[char_index].in_glyph;
317 if(glyph_index == -1){
321 float ky =
_glyphs[glyph_index].y;
322 unsigned span_index =
_characters[char_index].in_span;
348 unsigned lc_index = char_index;
349 unsigned hold_iisi =
_spans[span_index].in_input_stream_item;
353 if(glyph_index == -1){
359 text_string += *text_iter;
363 if(lc_index ==
_glyphs[glyph_index].in_character){
364 cwidth = rtl *
_glyphs[glyph_index].advance;
382 hold_dx[ndx++] = fabs(cwidth);
395 if(newtarget != oldtarget)
break;
397 unsigned next_span_index =
_characters[lc_index].in_span;
398 if(span_index != next_span_index){
415 if(hold_iisi !=
_spans[next_span_index].in_input_stream_item)
break;
416 if(fabs(char_x -
_spans[next_span_index].x_start) >= 1e-4)
break;
423 span_index = next_span_index;
424 text_iter =
_spans[span_index].input_stream_first_character;
429 ctx->
bind(glyph_matrix, 1.0);
436 ctx->
text(smuggle_string, g_pos, text_source->
style);
437 free(smuggle_string);
440 char_index = lc_index;
449 std::vector<CairoGlyphInfo> glyphtext;
453 bool second_pass =
false;
455 for (
unsigned pass = 0; pass <= second_pass; pass++) {
456 for (
unsigned glyph_index = 0 ; glyph_index <
_glyphs.size() ; ) {
459 unsigned same_character =
_glyphs[glyph_index].in_character;
460 while (
_glyphs[glyph_index].in_character == same_character) {
462 if (glyph_index ==
_glyphs.size())
476 unsigned char_index =
_glyphs[glyph_index].in_character;
477 unsigned original_span =
_characters[char_index].in_span;
478 while (char_index &&
_characters[char_index - 1].in_span == original_span) {
484 Glib::ustring span_string;
486 unsigned int first_index = glyph_index;
489 span_string += *span_iter;
492 unsigned same_character =
_glyphs[glyph_index].in_character;
493 while (glyph_index <
_glyphs.size() &&
_glyphs[glyph_index].in_character == same_character) {
494 if (glyph_index != first_index)
495 glyph_matrix =
_glyphs[glyph_index].transform(*
this);
500 info.
x = glyph_matrix[4];
501 info.
y = glyph_matrix[5];
503 glyphtext.push_back(info);
507 }
while (glyph_index <
_glyphs.size()
509 && (font_matrix * glyph_matrix.
inverse()).isIdentity()
515 flip_matrix[3] = -1.0;
516 font_matrix = flip_matrix * font_matrix;
519 float opacity = SP_SCALE24_TO_FLOAT(style->
opacity.value);
521 if (opacity != 1.0) {
526 if (glyph_index - first_index > 0) {
527 second_pass |= ctx->
renderGlyphtext(span.
font->get_font(), font_matrix, glyphtext, style, pass);
529 if (opacity != 1.0) {
537#if DEBUG_TEXTLAYOUT_DUMPASTEXT
553 case PANGO_STYLE_NORMAL:
return "upright";
554 case PANGO_STYLE_ITALIC:
return "italic";
555 case PANGO_STYLE_OBLIQUE:
return "oblique";
563 case PANGO_WEIGHT_THIN :
return "thin";
564 case PANGO_WEIGHT_ULTRALIGHT:
return "ultralight";
565 case PANGO_WEIGHT_LIGHT :
return "light";
566 case PANGO_WEIGHT_SEMILIGHT :
return "semilight";
567 case PANGO_WEIGHT_BOOK :
return "book";
568 case PANGO_WEIGHT_NORMAL :
return "normalweight";
569 case PANGO_WEIGHT_MEDIUM :
return "medium";
570 case PANGO_WEIGHT_SEMIBOLD :
return "semibold";
571 case PANGO_WEIGHT_BOLD :
return "bold";
572 case PANGO_WEIGHT_ULTRABOLD :
return "ultrabold";
573 case PANGO_WEIGHT_HEAVY :
return "heavy";
574 case PANGO_WEIGHT_ULTRAHEAVY:
return "ultraheavy";
576 return std::to_string(
w);
582 if (span_index >=
_spans.size())
585 if (
_spans[span_index].font) {
592#if DEBUG_TEXTLAYOUT_DUMPASTEXT
596 Glib::ustring::const_iterator icc;
601 unsigned lastspan=5000;
605 icc =
_spans[lastspan].input_stream_first_character;
607 snprintf(line,
sizeof(line),
"char %4u: '%c' 0x%4.4x x=%8.4f glyph=%3d span=%3d\n", j, *icc, *icc,
_characters[j].x,
_characters[j].in_glyph,
_characters[j].in_span);
613 for(
unsigned j = 0; j <
_glyphs.size() ; j++){
614 snprintf(line,
sizeof(line),
"glyph %4u: %4d (%8.4f,%8.4f) rot=%8.4f cx=%8.4f char=%4d\n",
620 for (
unsigned span_index = 0 ; span_index <
_spans.size() ; span_index++) {
621 result += Glib::ustring::compose(
"==== span %1 \n", span_index)
622 + Glib::ustring::compose(
" in para %1 (direction=%2)\n",
_lines[
_chunks[
_spans[span_index].in_chunk].in_line].in_paragraph,
624 + Glib::ustring::compose(
" in source %1 (type=%2, cookie=%3)\n",
_spans[span_index].in_input_stream_item,
627 + Glib::ustring::compose(
" in line %1 (baseline=%2, shape=%3)\n",
_chunks[
_spans[span_index].in_chunk].in_line,
630 + Glib::ustring::compose(
" in chunk %1 (x=%2, baselineshift=%3)\n",
_spans[span_index].in_chunk,
_chunks[
_spans[span_index].in_chunk].left_x,
_spans[span_index].baseline_shift);
632 if (
_spans[span_index].font) {
633 const char* variations = pango_font_description_get_variations(
_spans[span_index].font->descr);
634 result += Glib::ustring::compose(
635 " font '%1' %2 %3 %4 %5\n",
637 _spans[span_index].font_size,
640 (variations?variations:
"")
643 result += Glib::ustring::compose(
" x_start = %1, x_end = %2\n",
_spans[span_index].x_start,
_spans[span_index].x_end)
644 + Glib::ustring::compose(
" line height: ascent %1, descent %2\n",
_spans[span_index].line_height.ascent,
_spans[span_index].line_height.descent)
646 +
" ** characters:\n";
647 Glib::ustring::const_iterator iter_char =
_spans[span_index].input_stream_first_character;
649 for (
unsigned char_index = 0 ; char_index <
_characters.size() ; char_index++) {
650 union {
const PangoLogAttr* pattr;
const unsigned* uattr;} u;
651 u.pattr = &
_characters[char_index].char_attributes;
652 if (
_characters[char_index].in_span != span_index)
continue;
654 snprintf(line,
sizeof(line),
" %u: control x=%f flags=%03x glyph=%d\n", char_index,
_characters[char_index].x, *u.uattr,
_characters[char_index].in_glyph);
656 snprintf(line,
sizeof(line),
" %u: '%c' 0x%4.4x x=%f flags=%03x glyph=%d\n", char_index, *iter_char, *iter_char,
_characters[char_index].x, *u.uattr,
_characters[char_index].in_glyph);
661 result +=
" ** glyphs:\n";
662 for (
unsigned glyph_index = 0 ; glyph_index <
_glyphs.size() ; glyph_index++) {
664 snprintf(line,
sizeof(line),
" %u: %d (%f,%f) rot=%f cx=%f char=%d\n", glyph_index,
_glyphs[glyph_index].glyph,
_glyphs[glyph_index].x,
_glyphs[glyph_index].y,
_glyphs[glyph_index].rotation,
_glyphs[glyph_index].
width,
_glyphs[glyph_index].in_character);
678 if (startOffset.
_set) {
700 if (
offset >= 0.0 && point_otp !=
nullptr && point_otp[0].piece >= 0) {
703 const_cast<Path&
>(path).PointAndTangentAt(point_otp[0].piece, point_otp[0].t, point, tangent);
713 for (
unsigned char_index = 0 ; char_index <
_characters.size() ; ) {
716 size_t next_cluster_char_index = 0;
717 for (next_cluster_char_index = char_index + 1 ; next_cluster_char_index <
_characters.size() ; next_cluster_char_index++) {
718 if (
_characters[next_cluster_char_index].in_glyph != -1 &&
_characters[next_cluster_char_index].char_attributes.is_cursor_position)
724 size_t next_cluster_glyph_index = 0;
725 if (next_cluster_char_index ==
_characters.size()) {
726 next_cluster_glyph_index =
_glyphs.size();
728 next_cluster_glyph_index =
_characters[next_cluster_char_index].in_glyph;
732 double cluster_width = 0.0;
733 size_t const current_cluster_glyph_index =
_characters[char_index].in_glyph;
734 for (
size_t glyph_index = current_cluster_glyph_index ; glyph_index < next_cluster_glyph_index ; glyph_index++)
736 cluster_width +=
_glyphs[glyph_index].advance;
741 start_offset -= cluster_width;
743 double end_offset = start_offset + cluster_width;
746 double midpoint_offset = (start_offset + end_offset) * 0.5;
749 if (midpoint_offset >= 0.0 && midpoint_otp !=
nullptr && midpoint_otp[0].piece >= 0) {
752 const_cast<Path&
>(path).PointAndTangentAt(midpoint_otp[0].piece, midpoint_otp[0].t, midpoint, tangent);
754 if (start_offset >= 0.0 && end_offset >= 0.0) {
756 if (start_otp !=
nullptr && start_otp[0].piece >= 0) {
758 if (end_otp !=
nullptr && end_otp[0].piece >= 0) {
759 bool on_same_subpath =
true;
760 for (
const auto & pt : path.
pts) {
761 if (pt.piece <= start_otp[0].
piece)
continue;
762 if (pt.piece >= end_otp[0].
piece)
break;
764 on_same_subpath =
false;
768 if (on_same_subpath) {
771 const_cast<Path&
>(path).PointAt(start_otp[0].piece, start_otp[0].t, startpoint);
772 const_cast<Path&
>(path).PointAt(end_otp[0].piece, end_otp[0].t, endpoint);
773 if (endpoint != startpoint) {
774 tangent = endpoint - startpoint;
786 for (
size_t glyph_index = current_cluster_glyph_index; glyph_index < next_cluster_glyph_index ; glyph_index++) {
789 _glyphs[glyph_index].rotation += rotation;
793 for (
size_t glyph_index = current_cluster_glyph_index; glyph_index < next_cluster_glyph_index ; glyph_index++) {
797 tangent_shift += cluster_width;
801 _glyphs[glyph_index].rotation += rotation;
809 g_free(midpoint_otp);
811 char_index = next_cluster_char_index;
814 for (
auto & _span :
_spans) {
832 Span const &span =
_glyphs[glyph_index].span(
this);
848 for (
auto & _glyph :
_glyphs) {
876 for (std::vector<Span>::const_iterator it_span =
_spans.begin() ; it_span !=
_spans.end() ; it_span++) {
878 if (it_span ==
_spans.end() - 1 || (it_span + 1)->in_chunk != it_span->in_chunk)
879 length += it_span->x_end;
890 out <<
" emSize: " << f.
emSize()
891 <<
" ascent: " << f.
ascent
898 out <<
" emSize: " << f->
emSize()
899 <<
" ascent: " << f->
ascent
TODO: insert short description here.
Declaration of CairoRenderContext, a class used for rendering with Cairo.
FontInstance provides metrics, OpenType data, and glyph curves/pixbufs for a font.
double GetXHeight() const
double GetTypoDescent() const
double GetMaxAscent() const
double GetMaxDescent() const
double GetTypoAscent() const
3x3 matrix representing an affine transformation.
Point translation() const
Gets the translation imparted by the Affine.
void setIdentity()
Sets this matrix to be the Identity Affine.
Affine inverse() const
Compute the inverse matrix.
void unionWith(CRect const &b)
Enlarge the rectangle to contain the argument.
Axis-aligned rectangle that can be empty.
Two-dimensional point that doubles as a vector.
void normalize()
Normalize the vector representing the point.
constexpr Coord y() const noexcept
constexpr Coord x() const noexcept
Rotation around the origin.
bool renderGlyphtext(PangoFont *font, Geom::Affine const &font_matrix, std::vector< CairoGlyphInfo > const &glyphtext, SPStyle const *style, bool second_pass=false)
Called by Layout-TNG-Output, this function decides how to apply styles and write out the final shapes...
void setStateForStyle(SPStyle const *style)
void popLayer(cairo_operator_t composite=CAIRO_OPERATOR_CLEAR)
Keep track of font metrics.
void set(FontInstance const *font)
void max(FontMetrics const &other)
Save the larger values of ascent and descent between this and other.
void computeEffective(const double &line_height)
Calculate the effective ascent and descent including half "leading".
Represents a text item in the input stream.
SPStyle * style
in characters, from text_start to text_end only
Holds a position within the glyph output of Layout.
Generates the layout for either wrapped or non-wrapped text and stores the result.
void transform(Geom::Affine const &transform)
Apply the given transform to all the output presently stored in this object.
LengthAdjust lengthAdjust
How do we meet textLength if specified: by letterspacing or by scaling horizontally.
Geom::OptRect bounds(Geom::Affine const &transform, bool with_stroke=false, int start=-1, int length=-1) const
Calculates the smallest rectangle completely enclosing all the glyphs.
std::vector< Line > _lines
Alignment
For expressing paragraph alignment.
double getTextLengthMultiplierDue() const
Get the actual scale multiplier if it's due with the current values of above stuff,...
std::vector< Glyph > _glyphs
std::vector< Chunk > _chunks
void _clearOutputObjects()
Erases all the stuff output by computeFlow().
Direction _blockProgression() const
The overall block-progression of the whole flow.
struct Inkscape::Text::Layout::CursorShape _empty_cursor_shape
double textLengthIncrement
This one is used by letterspacing strategy: to each glyph width, this is added.
Glib::ustring dumpAsText() const
debug and unit test method.
void show(DrawingGroup *in_arena, StyleAttachments &style_attachments, Geom::OptRect const &paintbox) const
Adds all the output glyphs to in_arena using the given paintbox.
Glib::ustring getFontFamily(unsigned span_index) const
Returns the font family of the indexed span.
void fitToPathAlign(SVGLength const &startOffset, Path const &path)
Moves all the glyphs in the structure so that the baseline of all the characters sits neatly along th...
std::vector< Paragraph > _paragraphs
static bool _directions_are_orthogonal(Direction d1, Direction d2)
so that LEFT_TO_RIGHT == RIGHT_TO_LEFT but != TOP_TO_BOTTOM
iterator end() const
Returns an iterator pointing just past the end of the last glyph, which is also just past the end of ...
double textLengthMultiplier
By how much each character needs to be wider or narrower, using the specified lengthAdjust strategy,...
double getActualLength() const
Get actual length of layout, by summing span lengths.
double getTextLengthIncrementDue() const
Get the actual spacing increment if it's due with the current values of above stuff,...
SVGLength textLength
Gives the length target of this layout, as given by textLength attribute.
std::vector< InputStreamItem * > _input_stream
This is our internal storage for all the stuff passed to the appendText() and appendControlCode() fun...
void print(SPPrintContext *ctx, Geom::OptRect const &pbox, Geom::OptRect const &dbox, Geom::OptRect const &bbox, Geom::Affine const &ctm) const
Sends all the glyphs to the given print context.
double _getChunkWidth(unsigned chunk_index) const
calculates the width of a chunk, which is the largest x coordinate (start or end) of the spans contai...
SPCurve convertToCurves() const
std::vector< Character > _characters
void showGlyphs(CairoRenderContext *ctx) const
Renders all the glyphs to the given Cairo rendering context.
Direction
Used to specify any particular text direction required.
Path const * _path_fitted
as passed to fitToPathAlign()
@ LENGTHADJUST_SPACINGANDGLYPHS
iterator begin() const
Returns an iterator pointing at the first glyph of the flowed output.
std::vector< Span > _spans
void attachFill(DrawingText *item, SPPaintServer *paintserver, Geom::OptRect const &bbox)
void attachStroke(DrawingText *item, SPPaintServer *paintserver, Geom::OptRect const &bbox)
void attachFilter(DrawingText *item, SPFilter *filter)
Path and its polyline approximation.
std::vector< path_lineto > pts
Wrapper around a Geom::PathVector object.
T< SPAttr::FILL, SPIPaint > fill
fill
T< SPAttr::STROKE, SPIPaint > stroke
stroke
SPITextDecorationData text_decoration_data
T< SPAttr::OPACITY, SPIScale24 > opacity
opacity
static char const *const parent
Group belonging to an SVG drawing element.
char const * sp_font_description_get_family(PangoFontDescription const *fontDescr)
TODO: insert short description here.
The data describing a single loaded font.
char * smuggle_adxkyrtl_in(const char *string, int ndx, float *adx, float ky, float rtl)
static char const * direction_to_text(Layout::Direction d)
static char const * style_to_text(PangoStyle s)
static std::string weight_to_text(PangoWeight w)
Helper class to stream background task notifications as a series of messages.
PathVector - a sequence of subpaths.
Geom::Affine transform(Layout const &layout) const
unsigned in_input_stream_item
See CSS3 section 3.2. The direction in which lines go.
Chunk const & chunk(Layout const *l) const
std::shared_ptr< FontInstance > font
Glib::ustring::const_iterator input_stream_first_character
Line const & line(Layout const *l) const
unsigned int bind(Geom::Affine const &transform, float opacity)
unsigned int fill(Geom::PathVector const &pathv, Geom::Affine const &ctm, SPStyle const *style, Geom::OptRect const &pbox, Geom::OptRect const &dbox, Geom::OptRect const &bbox)
unsigned int stroke(Geom::PathVector const &pathv, Geom::Affine const &ctm, SPStyle const *style, Geom::OptRect const &pbox, Geom::OptRect const &dbox, Geom::OptRect const &bbox)
unsigned int text(char const *text, Geom::Point p, SPStyle const *style)
Creates and maintains display tree needed for text styling.
SPStyle - a style object for SPItem objects.
Enhanced Metafile Input/Output.
int SingleUnicodeToNon(uint16_t text)
std::vector< Texture > unused