Layout-TNG-Output.cpp revision 9a8ade3834e2a67c1d95bcfc900ab36be37a03a5
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Inkscape::Text::Layout - text layout engine output functions
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Authors:
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Richard Hughes <cyreve@users.sf.net>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Copyright (C) 2005 Richard Hughes
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen * Released under GNU GPL, read the file 'COPYING' for more information
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm namespace Internal {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmusing Inkscape::Extension::Internal::CairoRenderContext;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm dx array (character widths) and
8c39cbeab9949a0a7d6ae66b768a7352019e42f8johanengelen ky (vertical kerning for entire span)
072916d0ef7dccd696b59381f50bcf776abccefbjohanengelen rtl (+1 for LTR, -1 RTL)
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud are smuggled through to the EMF (ignored by others) as:
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud text<nul>N w1 w2 w3 ...wN<nul>y1 y2 y3 .. yN<nul><nul>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm The ndx, widths, y kern, and rtl are all 7 characters wide. ndx and rtl are ints, the widths and ky are
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm formatted as ' 6f'.
8d9f5d586a04809427ce1df284a5720112177991cilixchar *smuggle_adxkyrtl_in(const char *string, int ndx, float *adx, float ky, float rtl){
c169f6cddd2da06cfb761339f445bbd8866f72a8buliabyak /* holds: string
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen fake terminator (one \0)
0cc5b8d2f7b87c4222ee3662071bef1cb1f22b06bgk Number of widths (ndx)
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen series of widths (ndx entries)
f4db63be4e929f4706410914295deccaceea19cdcilix fake terminator (one \0)
ab99111a42436818e6902e044c8f3af2b724263bcilix y kern value (one float)
76db360f5f052775326e6d406b9e1e9e2966e11acilix rtl value (one float)
3d0482af18ffb591c1d8ddecf516629e1bcd2ae4cilix real terminator (two \0)
044d712d4d03f8354962d54e47cfac2346a69ccccilix newsize = 8*((7 + newsize)/8); // suppress valgrind messages if it is a multiple of 8 bytes???
2f5c0701b333a695eedb1680beb1adf95c0723dacilix strcpy(smuggle,string); // text to pass, includes the first fake terminator
add2ffae3c4686b50d888775bbdf083a4726a210johanengelen char *cptr = smuggle + slen + 1; // immediately after the first fake terminator
29f9623ba77fc735b89765ae3a13e0c06aabafcecilix sprintf(cptr," %6d",(int) rtl); // rtl multiplier for span
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen for (std::vector<Span>::iterator it_span = _spans.begin() ; it_span != _spans.end() ; it_span++)
add2ffae3c4686b50d888775bbdf083a4726a210johanengelen if (other.leading > leading) leading = other.leading;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmvoid Layout::_getGlyphTransformMatrix(int glyph_index, Geom::Affine *matrix) const
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm double sin_rotation = sin(_glyphs[glyph_index].rotation);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm double cos_rotation = cos(_glyphs[glyph_index].rotation);
29f9623ba77fc735b89765ae3a13e0c06aabafcecilix if (span.block_progression == LEFT_TO_RIGHT || span.block_progression == RIGHT_TO_LEFT) {
29f9623ba77fc735b89765ae3a13e0c06aabafcecilix (*matrix)[4] = _lines[_chunks[span.in_chunk].in_line].baseline_y + _glyphs[glyph_index].y;
29f9623ba77fc735b89765ae3a13e0c06aabafcecilix (*matrix)[5] = _chunks[span.in_chunk].left_x + _glyphs[glyph_index].x;
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen (*matrix)[4] = _chunks[span.in_chunk].left_x + _glyphs[glyph_index].x;
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen (*matrix)[5] = _lines[_chunks[span.in_chunk].in_line].baseline_y + _glyphs[glyph_index].y;
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraudvoid Layout::show(DrawingGroup *in_arena, Geom::OptRect const &paintbox) const
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen for (unsigned span_index = 0 ; span_index < _spans.size() ; span_index++) {
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud if (_input_stream[_spans[span_index].in_input_stream_item]->Type() != TEXT_SOURCE) continue;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[_spans[span_index].in_input_stream_item]);
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen text_source->style->text_decoration_data.tspan_width = _spans[span_index].width();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm text_source->style->text_decoration_data.ascender = _spans[span_index].line_height.getAscent();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm text_source->style->text_decoration_data.descender = _spans[span_index].line_height.getDescent();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm text_source->style->text_decoration_data.line_gap = _spans[span_index].line_height.getLeading();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm (_chunks[_spans[span_index].in_chunk].in_line != _chunks[_spans[span_index-1].in_chunk].in_line)){
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm text_source->style->text_decoration_data.tspan_line_start = true;
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen text_source->style->text_decoration_data.tspan_line_start = false;
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen (_chunks[_spans[span_index].in_chunk].in_line != _chunks[_spans[span_index+1].in_chunk].in_line)){
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen text_source->style->text_decoration_data.tspan_line_end = true;
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen text_source->style->text_decoration_data.tspan_line_end = false;
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen double underline_thickness, underline_position, line_through_thickness,line_through_position;
70eb1fc448cb08acf3468f80fa2296c03b32afd2cilix _spans[span_index].font->FontDecoration(underline_position, underline_thickness, line_through_position, line_through_thickness);
c169f6cddd2da06cfb761339f445bbd8866f72a8buliabyak text_source->style->text_decoration_data.underline_thickness = underline_thickness;
c169f6cddd2da06cfb761339f445bbd8866f72a8buliabyak text_source->style->text_decoration_data.underline_position = underline_position;
c169f6cddd2da06cfb761339f445bbd8866f72a8buliabyak text_source->style->text_decoration_data.line_through_thickness = line_through_thickness;
6f4a90e526af850ffc36064f58f09c190f3b633fjohanengelen text_source->style->text_decoration_data.line_through_position = line_through_position;
6f4a90e526af850ffc36064f58f09c190f3b633fjohanengelen else { // can this case ever occur?
f4db63be4e929f4706410914295deccaceea19cdcilix text_source->style->text_decoration_data.underline_thickness =
f4db63be4e929f4706410914295deccaceea19cdcilix text_source->style->text_decoration_data.underline_position =
f4db63be4e929f4706410914295deccaceea19cdcilix text_source->style->text_decoration_data.line_through_thickness =
ab99111a42436818e6902e044c8f3af2b724263bcilix text_source->style->text_decoration_data.line_through_position = 0.0;
76db360f5f052775326e6d406b9e1e9e2966e11acilix DrawingText *nr_text = new DrawingText(in_arena->drawing());
3d0482af18ffb591c1d8ddecf516629e1bcd2ae4cilix while (glyph_index < (int)_glyphs.size() && _characters[_glyphs[glyph_index].in_character].in_span == span_index) {
3d0482af18ffb591c1d8ddecf516629e1bcd2ae4cilix if (_characters[_glyphs[glyph_index].in_character].in_glyph != -1) {
64aee804a6a47424f7994e60558351b8cf2ea4dbcilix if(first_line_glyph && text_source->style->text_decoration_data.tspan_line_start){
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix // save the starting coordinates for the line - these are needed for figuring out dot/dash/wave phase
044d712d4d03f8354962d54e47cfac2346a69ccccilix (void) nr_text->addComponent(_spans[span_index].font, _glyphs[glyph_index].glyph, glyph_matrix,
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmGeom::OptRect Layout::bounds(Geom::Affine const &transform, int start, int length) const
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; glyph_index++) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (_characters[_glyphs[glyph_index].in_character].in_glyph == -1) continue;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (start != -1 && (int) _glyphs[glyph_index].in_character < start) continue;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if ((int) _glyphs[glyph_index].in_character > start + length) continue;
6656f193fdace606d1b162d6dea0223bc295f0a6cilix // this could be faster
6656f193fdace606d1b162d6dea0223bc295f0a6cilix Geom::OptRect glyph_rect = _glyphs[glyph_index].span(this).font->BBox(_glyphs[glyph_index].glyph);
6656f193fdace606d1b162d6dea0223bc295f0a6cilix/* This version is much simpler than the old one
6656f193fdace606d1b162d6dea0223bc295f0a6cilix Geom::OptRect const &pbox, Geom::OptRect const &dbox, Geom::OptRect const &bbox,
77a4a003111bd5cfb771d4849801c898aeb889b0cilixfloat hold_dx[MAX_DX]; // For smuggling dx values (character widths) into print functions, unlikely any simple text output will be longer than this.
9ce14357bb94b9dd92ad40bf43ef435a257b355acilixdouble rtl = 1.0; // 1 L->R, -1 R->L, constant across a span. 1.0 for t->b b->t???
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; glyph_index++) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (_characters[_glyphs[glyph_index].in_character].in_glyph == -1)continue; //invisible glyphs
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Span const &span = _spans[_characters[_glyphs[glyph_index].in_character].in_span];
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Geom::PathVector const * pv = span.font->PathVector(_glyphs[glyph_index].glyph);
eaa9bdc7bf7b73397e536edd47490d84e4420bd8bryce InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[span.in_input_stream_item]);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm sp_print_fill(ctx, temp_pv, ctm, text_source->style, pbox, dbox, bbox);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm sp_print_stroke(ctx, temp_pv, ctm, text_source->style, pbox, dbox, bbox);
c90010388b0d4045c26e81c2be28beedcb36c7d3cilix /* index by characters, referencing glyphs and spans only as needed */
77a4a003111bd5cfb771d4849801c898aeb889b0cilix int doUTN = CanUTN(); // Unicode to Nonunicode translation enabled if true
262d0c3f05130d86368d95f110aa8ccab5f83e5ccilix for (unsigned char_index = 0 ; char_index < _characters.size() ; ) {
262d0c3f05130d86368d95f110aa8ccab5f83e5ccilix Glib::ustring text_string; // accumulate text for record in this
262d0c3f05130d86368d95f110aa8ccab5f83e5ccilix Geom::Point g_pos(0,0); // all strings are output at (0,0) because we do the translation using the matrix
262d0c3f05130d86368d95f110aa8ccab5f83e5ccilix if(glyph_index == -1){ // if the character maps to an invisible glyph we cannot know its geometry, so skip it and move on
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgk ky = _glyphs[glyph_index].y; // same value for all positions in a span
2d107ef9730aff3f4d776ae0c2f7d983e289ce02joncruz unsigned span_index = _characters[char_index].in_span;
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgk Glib::ustring::const_iterator text_iter = span.input_stream_first_character;
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgk InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[span.in_input_stream_item]);
77a4a003111bd5cfb771d4849801c898aeb889b0cilix glyph_matrix = Geom::Scale(1.0, -1.0) * (Geom::Affine)Geom::Rotate(_glyphs[glyph_index].rotation);
147c8e03bb214f85cd5906ddc6413c4293c4baa9cilix if (block_progression == LEFT_TO_RIGHT || block_progression == RIGHT_TO_LEFT) {
147c8e03bb214f85cd5906ddc6413c4293c4baa9cilix glyph_matrix[4] = span.line(this).baseline_y + span.baseline_shift;
147c8e03bb214f85cd5906ddc6413c4293c4baa9cilix // since we're outputting character codes, not glyphs, we want the character x
77a4a003111bd5cfb771d4849801c898aeb889b0cilix glyph_matrix[5] = span.chunk(this).left_x + span.x_start + _characters[_glyphs[glyph_index].in_character].x;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix glyph_matrix[4] = span.chunk(this).left_x + span.x_start + _characters[_glyphs[glyph_index].in_character].x;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix glyph_matrix[5] = span.line(this).baseline_y + span.baseline_shift;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix if(doUTN)oldtarget=SingleUnicodeToNon(*text_iter); // this should only ever be with a 1:1 glyph:character situation
77a4a003111bd5cfb771d4849801c898aeb889b0cilix // accumulate a record to write
77a4a003111bd5cfb771d4849801c898aeb889b0cilix unsigned hold_iisi = _spans[span_index].in_input_stream_item;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix if(glyph_index == -1){ // end of a line within a paragraph, for instance
97a20864afec63a0b7bb757b628ee2ae596cf648cilix // always append if here
97a20864afec63a0b7bb757b628ee2ae596cf648cilix // figure out char widths, used by EMF, not currently used elsewhere
97a20864afec63a0b7bb757b628ee2ae596cf648cilix if(lc_index == _glyphs[glyph_index].in_character){ // Glyph width is used only for the first character, these may be 0
77a4a003111bd5cfb771d4849801c898aeb889b0cilix cwidth = rtl * _glyphs[glyph_index].width; // width might be zero
77a4a003111bd5cfb771d4849801c898aeb889b0cilixstd:: cout << "DEBUG Layout::print in while "
77a4a003111bd5cfb771d4849801c898aeb889b0cilix<< " char_index " << char_index
77a4a003111bd5cfb771d4849801c898aeb889b0cilix<< " lc_index " << lc_index
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm<< " character " << std::hex << (int) *text_iter << std::dec
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm<< " glyph_index " << glyph_index
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm<< " glyph_xy " << _glyphs[glyph_index].x << " , " << _glyphs[glyph_index].y
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm<< " span_index " << span_index
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm<< " hold_iisi " << hold_iisi
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm<< std::endl; //DEBUG
a2fbdfc8e80d3d1845bf0d5df989726ae2ffd5bfjohanengelen else { // silently truncate any text line silly enough to be longer than MAX_DX
46c4893a7458eda6edcd064121bc000634af7a09johanengelen // conditions that prevent this character from joining the record
46c4893a7458eda6edcd064121bc000634af7a09johanengelen if(lc_index >= _characters.size()) break; // nothing more to process, so it must be the end of the record
46c4893a7458eda6edcd064121bc000634af7a09johanengelen if(doUTN)newtarget=SingleUnicodeToNon(*text_iter); // this should only ever be with a 1:1 glyph:character situation
46c4893a7458eda6edcd064121bc000634af7a09johanengelen if(newtarget != oldtarget)break; // change in unicode to nonunicode translation status
46c4893a7458eda6edcd064121bc000634af7a09johanengelen // MUST exit on any major span change, but not on some little events, like a font substitution event irrelvant for the file save
46c4893a7458eda6edcd064121bc000634af7a09johanengelen unsigned next_span_index = _characters[lc_index].in_span;
46c4893a7458eda6edcd064121bc000634af7a09johanengelen /* on major changes break out of loop.
46c4893a7458eda6edcd064121bc000634af7a09johanengelen 1st case usually indicates an entire input line has been processed (out of several in a paragraph)
46c4893a7458eda6edcd064121bc000634af7a09johanengelen 2nd case usually indicates that a format change within a line (font/size/color/etc) is present.
46c4893a7458eda6edcd064121bc000634af7a09johanengelenstd:: cout << "DEBUG Layout::print in while --- "
46c4893a7458eda6edcd064121bc000634af7a09johanengelen<< " char_index " << char_index
46c4893a7458eda6edcd064121bc000634af7a09johanengelen<< " lc_index " << lc_index
46c4893a7458eda6edcd064121bc000634af7a09johanengelen<< " cwidth " << cwidth
46c4893a7458eda6edcd064121bc000634af7a09johanengelen<< " _char.x (next) " << (lc_index < _characters.size() ? _characters[lc_index].x : -1)
46c4893a7458eda6edcd064121bc000634af7a09johanengelen<< " char_x (end this)" << char_x
46c4893a7458eda6edcd064121bc000634af7a09johanengelen<< " diff " << fabs(char_x - _characters[lc_index].x)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm<< " oldy " << ky
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm<< " nexty " << _glyphs[_characters[lc_index].in_glyph].y
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm<< std::endl; //DEBUG
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if(hold_iisi != _spans[next_span_index].in_input_stream_item)break; // major change, font, size, color, etc, must exit
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if(fabs(char_x - _spans[next_span_index].x_start) >= 1e-4)break; // xkerning change
ecda720053ff791e35dae3c5c1177bc225b6cdf1johanengelen if(ky != _glyphs[_characters[lc_index].in_glyph].y)break; // ykerning change
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm None of the above? Then this is a minor "pangito", update span_index and keep going.
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm The font used by the display may have failed over, but print does not care and can continue to use
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm whatever was specified in the XML.
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm text_iter = _spans[span_index].input_stream_first_character;
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen // the dx array is smuggled through to the EMF driver (ignored by others) as:
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen // text<nul>w1 w2 w3 ...wn<nul><nul>
2d107ef9730aff3f4d776ae0c2f7d983e289ce02joncruz // where the widths are floats 7 characters wide, including the space
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen char *smuggle_string=smuggle_adxkyrtl_in(text_string.c_str(),ndx, &hold_dx[0], ky, rtl);
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen sp_print_text(ctx, smuggle_string, g_pos, text_source->style);
0fc5ce7045233dae7e15fdc86774370f1b1d73cbjohanengelenvoid Layout::showGlyphs(CairoRenderContext *ctx) const
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm bool clip_mode = false;//(ctx->getRenderMode() == CairoRenderContext::RENDER_MODE_CLIP);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; ) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (_characters[_glyphs[glyph_index].in_character].in_glyph == -1) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm // invisible glyphs
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm unsigned same_character = _glyphs[glyph_index].in_character;
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen while (_glyphs[glyph_index].in_character == same_character)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Span const &span = _spans[_characters[_glyphs[glyph_index].in_character].in_span];
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[span.in_input_stream_item]);
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Geom::PathVector const *pathv = span.font->PathVector(_glyphs[glyph_index].glyph);
73d455c08e8062e257dd052d2d690b9300434351cilix Geom::PathVector pathv_trans = (*pathv) * glyph_matrix;
73d455c08e8062e257dd052d2d690b9300434351cilix ctx->renderPathVector(pathv_trans, style, Geom::OptRect());
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix Glib::ustring::const_iterator span_iter = span.input_stream_first_character;
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix unsigned char_index = _glyphs[glyph_index].in_character;
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix unsigned original_span = _characters[char_index].in_span;
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix while (char_index && _characters[char_index - 1].in_span == original_span) {
73d455c08e8062e257dd052d2d690b9300434351cilix // try to output as many characters as possible in one go
1e944d29efb206f5d0b5d1069cb098e22169d548cilix unsigned this_span_index = _characters[_glyphs[glyph_index].in_character].in_span;
5ce8d034d9fe78f969629cfe65d1a2518f173ba9cilix unsigned same_character = _glyphs[glyph_index].in_character;
1e944d29efb206f5d0b5d1069cb098e22169d548cilix while (glyph_index < _glyphs.size() && _glyphs[glyph_index].in_character == same_character) {
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix // this is the translation for x,y-offset
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix && (font_matrix * glyph_matrix.inverse()).isIdentity()
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix && _characters[_glyphs[glyph_index].in_character].in_span == this_span_index);
bb78cf2c3a2ee8ea2c98433128556847f03f5799cilix // remove vertical flip
732fb09f9c502000068a77667c3356cbbd5d39d5cilix float opacity = SP_SCALE24_TO_FLOAT(style->opacity.value);
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix ctx->renderGlyphtext(span.font->pFont, font_matrix, glyphtext, style);
73d455c08e8062e257dd052d2d690b9300434351cilix// these functions are for dumpAsText() only. No need to translate
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic char const *direction_to_text(Layout::Direction d)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm switch (d) {
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen return "???";
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen switch (s) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm return "???";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm switch (w) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm return "???";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmGlib::ustring Layout::getFontFamily(unsigned span_index) const
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen return sp_font_description_get_family(_spans[span_index].font->descr);
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen snprintf(line, sizeof(line), "spans %d\n", _spans.size());
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen snprintf(line, sizeof(line), "chars %d\n", _characters.size());
af8d25189f88abf89cdbe0e180e271c94079624fbuliabyak snprintf(line, sizeof(line), "glyphs %d\n", _glyphs.size());
a0334366488989ef25fb812d7030d298c0917c96johanengelen for(unsigned j = 0; j < _characters.size() ; j++){
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen icc = _spans[lastspan].input_stream_first_character;
a0334366488989ef25fb812d7030d298c0917c96johanengelen snprintf(line, sizeof(line), "char %4d: '%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);
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen snprintf(line, sizeof(line), "glyph %4d: %4d (%8.4f,%8.4f) rot=%8.4f cx=%8.4f char=%4d\n",
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen j, _glyphs[j].glyph, _glyphs[j].x, _glyphs[j].y, _glyphs[j].rotation, _glyphs[j].width, _glyphs[j].in_character);
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen for (unsigned span_index = 0 ; span_index < _spans.size() ; span_index++) {
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen snprintf(line, sizeof(line), "==== span %d \n", span_index);
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen snprintf(line, sizeof(line), " in para %d (direction=%s)\n", _lines[_chunks[_spans[span_index].in_chunk].in_line].in_paragraph,
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen direction_to_text(_paragraphs[_lines[_chunks[_spans[span_index].in_chunk].in_line].in_paragraph].base_direction));
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen snprintf(line, sizeof(line), " in source %d (type=%d, cookie=%p)\n", _spans[span_index].in_input_stream_item,
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen _input_stream[_spans[span_index].in_input_stream_item]->Type(),
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen _input_stream[_spans[span_index].in_input_stream_item]->source_cookie);
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen snprintf(line, sizeof(line), " in line %d (baseline=%f, shape=%d)\n", _chunks[_spans[span_index].in_chunk].in_line,
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen _lines[_chunks[_spans[span_index].in_chunk].in_line].baseline_y,
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen _lines[_chunks[_spans[span_index].in_chunk].in_line].in_shape);
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen snprintf(line, sizeof(line), " in chunk %d (x=%f, baselineshift=%f)\n", _spans[span_index].in_chunk, _chunks[_spans[span_index].in_chunk].left_x, _spans[span_index].baseline_shift);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm snprintf(line, sizeof(line), " font '%s' %f %s %s\n", sp_font_description_get_family(_spans[span_index].font->descr), _spans[span_index].font_size, style_to_text(pango_font_description_get_style(_spans[span_index].font->descr)), weight_to_text(pango_font_description_get_weight(_spans[span_index].font->descr)));
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen snprintf(line, sizeof(line), " x_start = %f, x_end = %f\n", _spans[span_index].x_start, _spans[span_index].x_end);
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen snprintf(line, sizeof(line), " line height: ascent %f, descent %f leading %f\n", _spans[span_index].line_height.ascent, _spans[span_index].line_height.descent, _spans[span_index].line_height.leading);
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen snprintf(line, sizeof(line), " direction %s, block-progression %s\n", direction_to_text(_spans[span_index].direction), direction_to_text(_spans[span_index].block_progression));
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen Glib::ustring::const_iterator iter_char = _spans[span_index].input_stream_first_character;
a797dcb8e284cab19f60b3eff93a53a62abda263johanengelen // very inefficent code. what the hell, it's only debug stuff.
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen for (unsigned char_index = 0 ; char_index < _characters.size() ; char_index++) {
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen union {const PangoLogAttr* pattr; const unsigned* uattr;} u;
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen u.pattr = &_characters[char_index].char_attributes;
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen if (_characters[char_index].in_span != span_index) continue;
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen if (_input_stream[_spans[span_index].in_input_stream_item]->Type() != TEXT_SOURCE) {
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen snprintf(line, sizeof(line), " %d: control x=%f flags=%03x glyph=%d\n", char_index, _characters[char_index].x, *u.uattr, _characters[char_index].in_glyph);
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen } else { // some text has empty tspans, iter_char cannot be dereferenced
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen snprintf(line, sizeof(line), " %d: '%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);
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; glyph_index++) {
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen if (_characters[_glyphs[glyph_index].in_character].in_span != span_index) continue;
42ba1b712b7b430669fc49aa9facb439181081becilix snprintf(line, sizeof(line), " %d: %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);
42ba1b712b7b430669fc49aa9facb439181081becilixvoid Layout::fitToPathAlign(SVGLength const &startOffset, Path const &path)
42ba1b712b7b430669fc49aa9facb439181081becilix offset = startOffset.computed * const_cast<Path&>(path).Length();
int unused = 0;
for (next_cluster_char_index = char_index + 1 ; next_cluster_char_index < _characters.size() ; next_cluster_char_index++) {
if (_characters[next_cluster_char_index].in_glyph != -1 && _characters[next_cluster_char_index].char_attributes.is_cursor_position)
for (size_t glyph_index = current_cluster_glyph_index ; glyph_index < next_cluster_glyph_index ; glyph_index++)
int unused = 0;
Path::cut_position *midpoint_otp = const_cast<Path&>(path).CurvilignToPosition(1, &midpoint_offset, unused);
const_cast<Path&>(path).PointAndTangentAt(midpoint_otp[0].piece, midpoint_otp[0].t, midpoint, tangent);
Path::cut_position *start_otp = const_cast<Path&>(path).CurvilignToPosition(1, &start_offset, unused);
bool on_same_subpath = true;
on_same_subpath = false;
if (on_same_subpath) {
for (size_t glyph_index = current_cluster_glyph_index; glyph_index < next_cluster_glyph_index ; glyph_index++) {
_glyphs[glyph_index].x = midpoint[Geom::Y] - tangent[Geom::X] * _glyphs[glyph_index].y - span.chunk(this).left_x;
_glyphs[glyph_index].y = midpoint[Geom::X] + tangent[Geom::Y] * _glyphs[glyph_index].y - _lines.front().baseline_y;
for (size_t glyph_index = current_cluster_glyph_index; glyph_index < next_cluster_glyph_index ; glyph_index++) {
double tangent_shift = -cluster_width * 0.5 + _glyphs[glyph_index].x - (_characters[char_index].x + span.x_start);
_glyphs[glyph_index].x = midpoint[Geom::X] + tangent[Geom::X] * tangent_shift - tangent[Geom::Y] * _glyphs[glyph_index].y - span.chunk(this).left_x;
_glyphs[glyph_index].y = midpoint[Geom::Y] + tangent[Geom::Y] * tangent_shift + tangent[Geom::X] * _glyphs[glyph_index].y - _lines.front().baseline_y;
_input_truncated = false;
_input_truncated = true;
for (int glyph_index = from_glyph._glyph_index ; glyph_index < to_glyph._glyph_index ; glyph_index++) {
if (pathv) {
if ( cc ) {
while (cc) {
return curve;