Layout-TNG-Output.cpp revision 9a8ade3834e2a67c1d95bcfc900ab36be37a03a5
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm/*
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Inkscape::Text::Layout - text layout engine output functions
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm *
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Authors:
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Richard Hughes <cyreve@users.sf.net>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm *
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm * Copyright (C) 2005 Richard Hughes
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm *
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen * Released under GNU GPL, read the file 'COPYING' for more information
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen */
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include <glib.h>
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "Layout-TNG.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "display/drawing-text.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "style.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "print.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "extension/print.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "livarot/Path.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "font-instance.h"
6656f193fdace606d1b162d6dea0223bc295f0a6cilix#include "svg/svg-length.h"
6656f193fdace606d1b162d6dea0223bc295f0a6cilix#include "extension/internal/cairo-render-context.h"
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#include "display/curve.h"
77a4a003111bd5cfb771d4849801c898aeb889b0cilix#include <2geom/pathvector.h>
77a4a003111bd5cfb771d4849801c898aeb889b0cilix#include "libunicode-convert/unicode-convert.h"
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilixnamespace Inkscape {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm namespace Extension {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm namespace Internal {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm class CairoRenderContext;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
d9c673867f424647c1586c356cc0ac1d34d0a98ajohanengelen }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmusing Inkscape::Extension::Internal::CairoRenderContext;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmusing Inkscape::Extension::Internal::CairoGlyphInfo;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelennamespace Inkscape {
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelennamespace Text {
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen/*
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm dx array (character widths) and
8c39cbeab9949a0a7d6ae66b768a7352019e42f8johanengelen ky (vertical kerning for entire span)
072916d0ef7dccd696b59381f50bcf776abccefbjohanengelen rtl (+1 for LTR, -1 RTL)
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud
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'.
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm*/
8d9f5d586a04809427ce1df284a5720112177991cilixchar *smuggle_adxkyrtl_in(const char *string, int ndx, float *adx, float ky, float rtl){
70eb1fc448cb08acf3468f80fa2296c03b32afd2cilix int slen = strlen(string);
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)
64aee804a6a47424f7994e60558351b8cf2ea4dbcilix */
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix int newsize=slen + 1 + 7 + 7*ndx + 1 + 7 + 7 + 2;
044d712d4d03f8354962d54e47cfac2346a69ccccilix newsize = 8*((7 + newsize)/8); // suppress valgrind messages if it is a multiple of 8 bytes???
61cfd957cd023c4f432ea0c7307784a56bf978e9cilix char *smuggle=(char *)malloc(newsize);
2f5c0701b333a695eedb1680beb1adf95c0723dacilix strcpy(smuggle,string); // text to pass, includes the first fake terminator
add2ffae3c4686b50d888775bbdf083a4726a210johanengelen char *cptr = smuggle + slen + 1; // immediately after the first fake terminator
e54ce05030e6aab675331e18f46f029f55ed1bf0cilix sprintf(cptr,"%07d",ndx); // number of widths to pass
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm cptr+=7; // advance over ndx
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm for(int i=0; i<ndx ; i++){ // all the widths
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm sprintf(cptr," %6f",adx[i]);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm cptr+=7; // advance over space + width
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm *cptr='\0';
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm cptr++; // second fake terminator
072916d0ef7dccd696b59381f50bcf776abccefbjohanengelen sprintf(cptr," %6f",ky); // y kern for span
8c39cbeab9949a0a7d6ae66b768a7352019e42f8johanengelen cptr+=7; // advance over space + ky
29f9623ba77fc735b89765ae3a13e0c06aabafcecilix sprintf(cptr," %6d",(int) rtl); // rtl multiplier for span
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud cptr+=7; // advance over rtl
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud *cptr++ = '\0'; // Set the real terminators
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud *cptr = '\0';
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm return(smuggle);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmvoid Layout::_clearOutputObjects()
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen{
8d9f5d586a04809427ce1df284a5720112177991cilix _paragraphs.clear();
70eb1fc448cb08acf3468f80fa2296c03b32afd2cilix _lines.clear();
c169f6cddd2da06cfb761339f445bbd8866f72a8buliabyak _chunks.clear();
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen for (std::vector<Span>::iterator it_span = _spans.begin() ; it_span != _spans.end() ; it_span++)
0cc5b8d2f7b87c4222ee3662071bef1cb1f22b06bgk if (it_span->font) it_span->font->Unref();
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen _spans.clear();
f4db63be4e929f4706410914295deccaceea19cdcilix _characters.clear();
b0c42c0dfcd02cc05126371948489a5a88b2e4b3cilix _glyphs.clear();
76db360f5f052775326e6d406b9e1e9e2966e11acilix _path_fitted = NULL;
3d0482af18ffb591c1d8ddecf516629e1bcd2ae4cilix}
64aee804a6a47424f7994e60558351b8cf2ea4dbcilix
b320a8d186114a5122ddc3afbe95110eb6cb10cecilixvoid Layout::LineHeight::max(LineHeight const &other)
044d712d4d03f8354962d54e47cfac2346a69ccccilix{
61cfd957cd023c4f432ea0c7307784a56bf978e9cilix if (other.ascent > ascent) ascent = other.ascent;
2f5c0701b333a695eedb1680beb1adf95c0723dacilix if (other.descent > descent) descent = other.descent;
add2ffae3c4686b50d888775bbdf083a4726a210johanengelen if (other.leading > leading) leading = other.leading;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmvoid Layout::_getGlyphTransformMatrix(int glyph_index, Geom::Affine *matrix) const
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Span const &span = _glyphs[glyph_index].span(this);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm double sin_rotation = sin(_glyphs[glyph_index].rotation);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm double cos_rotation = cos(_glyphs[glyph_index].rotation);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm (*matrix)[0] = span.font_size * cos_rotation;
8c39cbeab9949a0a7d6ae66b768a7352019e42f8johanengelen (*matrix)[1] = span.font_size * sin_rotation;
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen (*matrix)[2] = span.font_size * sin_rotation;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm (*matrix)[3] = -span.font_size * cos_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;
072916d0ef7dccd696b59381f50bcf776abccefbjohanengelen } else {
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;
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud }
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen}
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraudvoid Layout::show(DrawingGroup *in_arena, Geom::OptRect const &paintbox) const
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen{
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud int glyph_index = 0;
dc98accfae7a38326b92d74fa4330ac8ccb5b778jfbarraud double phase0 = 0.0;
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]);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
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();
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen if(!span_index ||
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;
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm else {
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen text_source->style->text_decoration_data.tspan_line_start = false;
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen }
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen if((span_index == _spans.size() -1) ||
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;
0563fd55cbad59e8a878e6d4cbbdd8e47f74488djohanengelen }
8d9f5d586a04809427ce1df284a5720112177991cilix else {
92fe3142613d000eff89db8a983b3b18b14eee79johanengelen text_source->style->text_decoration_data.tspan_line_end = false;
8d9f5d586a04809427ce1df284a5720112177991cilix }
70eb1fc448cb08acf3468f80fa2296c03b32afd2cilix if(_spans[span_index].font){
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 }
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;
ab99111a42436818e6902e044c8f3af2b724263bcilix }
ab99111a42436818e6902e044c8f3af2b724263bcilix
76db360f5f052775326e6d406b9e1e9e2966e11acilix DrawingText *nr_text = new DrawingText(in_arena->drawing());
76db360f5f052775326e6d406b9e1e9e2966e11acilix
b0c42c0dfcd02cc05126371948489a5a88b2e4b3cilix bool first_line_glyph = true;
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) {
3d0482af18ffb591c1d8ddecf516629e1bcd2ae4cilix Geom::Affine glyph_matrix;
64aee804a6a47424f7994e60558351b8cf2ea4dbcilix _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
64aee804a6a47424f7994e60558351b8cf2ea4dbcilix if(first_line_glyph && text_source->style->text_decoration_data.tspan_line_start){
64aee804a6a47424f7994e60558351b8cf2ea4dbcilix first_line_glyph = false;
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix phase0 = glyph_matrix.translation()[Geom::X];
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix }
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,
044d712d4d03f8354962d54e47cfac2346a69ccccilix _glyphs[glyph_index].width,
044d712d4d03f8354962d54e47cfac2346a69ccccilix _spans[span_index].line_height.getAscent(),
61cfd957cd023c4f432ea0c7307784a56bf978e9cilix _spans[span_index].line_height.getDescent(),
61cfd957cd023c4f432ea0c7307784a56bf978e9cilix glyph_matrix.translation()[Geom::X] - phase0
61cfd957cd023c4f432ea0c7307784a56bf978e9cilix );
2f5c0701b333a695eedb1680beb1adf95c0723dacilix }
2f5c0701b333a695eedb1680beb1adf95c0723dacilix glyph_index++;
2f5c0701b333a695eedb1680beb1adf95c0723dacilix }
add2ffae3c4686b50d888775bbdf083a4726a210johanengelen nr_text->setStyle(text_source->style);
add2ffae3c4686b50d888775bbdf083a4726a210johanengelen nr_text->setItemBounds(paintbox);
add2ffae3c4686b50d888775bbdf083a4726a210johanengelen in_arena->prependChild(nr_text);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmGeom::OptRect Layout::bounds(Geom::Affine const &transform, int start, int length) const
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Geom::OptRect bbox;
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 (length != -1) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (start == -1)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm start = 0;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if ((int) _glyphs[glyph_index].in_character > start + length) continue;
6656f193fdace606d1b162d6dea0223bc295f0a6cilix }
6656f193fdace606d1b162d6dea0223bc295f0a6cilix // this could be faster
6656f193fdace606d1b162d6dea0223bc295f0a6cilix Geom::Affine glyph_matrix;
6656f193fdace606d1b162d6dea0223bc295f0a6cilix _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
6656f193fdace606d1b162d6dea0223bc295f0a6cilix Geom::Affine total_transform = glyph_matrix;
6656f193fdace606d1b162d6dea0223bc295f0a6cilix total_transform *= transform;
6656f193fdace606d1b162d6dea0223bc295f0a6cilix if(_glyphs[glyph_index].span(this).font) {
6656f193fdace606d1b162d6dea0223bc295f0a6cilix Geom::OptRect glyph_rect = _glyphs[glyph_index].span(this).font->BBox(_glyphs[glyph_index].glyph);
6656f193fdace606d1b162d6dea0223bc295f0a6cilix if (glyph_rect) {
6656f193fdace606d1b162d6dea0223bc295f0a6cilix bbox.unionWith(*glyph_rect * total_transform);
6656f193fdace606d1b162d6dea0223bc295f0a6cilix }
6656f193fdace606d1b162d6dea0223bc295f0a6cilix }
6656f193fdace606d1b162d6dea0223bc295f0a6cilix }
6656f193fdace606d1b162d6dea0223bc295f0a6cilix return bbox;
6656f193fdace606d1b162d6dea0223bc295f0a6cilix}
6656f193fdace606d1b162d6dea0223bc295f0a6cilix
6656f193fdace606d1b162d6dea0223bc295f0a6cilix/* This version is much simpler than the old one
6656f193fdace606d1b162d6dea0223bc295f0a6cilix*/
6656f193fdace606d1b162d6dea0223bc295f0a6cilixvoid Layout::print(SPPrintContext *ctx,
6656f193fdace606d1b162d6dea0223bc295f0a6cilix Geom::OptRect const &pbox, Geom::OptRect const &dbox, Geom::OptRect const &bbox,
6656f193fdace606d1b162d6dea0223bc295f0a6cilix Geom::Affine const &ctm) const
6656f193fdace606d1b162d6dea0223bc295f0a6cilix{
6656f193fdace606d1b162d6dea0223bc295f0a6cilixbool text_to_path = ctx->module->textToPath();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmint oldtarget = 0;
fbb4eb8b63e74d9441220a73a8ca858425be4bd4johanengelenint newtarget = 0;
71146abe8aba032d73788a625fee5769a581bd3ccilix#define MAX_DX 2048
77a4a003111bd5cfb771d4849801c898aeb889b0cilixfloat hold_dx[MAX_DX]; // For smuggling dx values (character widths) into print functions, unlikely any simple text output will be longer than this.
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilixfloat ky; // For smuggling y kern value for span
fbb4eb8b63e74d9441220a73a8ca858425be4bd4johanengelenint ndx = 0;
9ce14357bb94b9dd92ad40bf43ef435a257b355acilixdouble rtl = 1.0; // 1 L->R, -1 R->L, constant across a span. 1.0 for t->b b->t???
9ce14357bb94b9dd92ad40bf43ef435a257b355acilixGeom::Affine glyph_matrix;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
71146abe8aba032d73788a625fee5769a581bd3ccilix if (_input_stream.empty()) return;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (!_glyphs.size()) return; // yes, this can happen.
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (text_to_path || _path_fitted) {
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 if (pv) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Geom::PathVector temp_pv = (*pv) * glyph_matrix;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (!text_source->style->fill.isNone())
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm sp_print_fill(ctx, temp_pv, ctm, text_source->style, pbox, dbox, bbox);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (!text_source->style->stroke.isNone())
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm sp_print_stroke(ctx, temp_pv, ctm, text_source->style, pbox, dbox, bbox);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
c90010388b0d4045c26e81c2be28beedcb36c7d3cilix }
c90010388b0d4045c26e81c2be28beedcb36c7d3cilix }
c90010388b0d4045c26e81c2be28beedcb36c7d3cilix else {
c90010388b0d4045c26e81c2be28beedcb36c7d3cilix /* index by characters, referencing glyphs and spans only as needed */
c90010388b0d4045c26e81c2be28beedcb36c7d3cilix double char_x;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix int doUTN = CanUTN(); // Unicode to Nonunicode translation enabled if true
77a4a003111bd5cfb771d4849801c898aeb889b0cilix Direction block_progression = _blockProgression();
77a4a003111bd5cfb771d4849801c898aeb889b0cilix
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 int glyph_index = _characters[char_index].in_glyph;
262d0c3f05130d86368d95f110aa8ccab5f83e5ccilix if(glyph_index == -1){ // if the character maps to an invisible glyph we cannot know its geometry, so skip it and move on
77a4a003111bd5cfb771d4849801c898aeb889b0cilix char_index++;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix continue;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix }
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgk ky = _glyphs[glyph_index].y; // same value for all positions in a span
2d107ef9730aff3f4d776ae0c2f7d983e289ce02joncruz unsigned span_index = _characters[char_index].in_span;
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgk Span const &span = _spans[span_index];
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgk char_x = 0.0;
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 } else {
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 }
77a4a003111bd5cfb771d4849801c898aeb889b0cilix switch(span.direction){
77a4a003111bd5cfb771d4849801c898aeb889b0cilix case Layout::TOP_TO_BOTTOM:
77a4a003111bd5cfb771d4849801c898aeb889b0cilix case Layout::BOTTOM_TO_TOP:
77a4a003111bd5cfb771d4849801c898aeb889b0cilix case Layout::LEFT_TO_RIGHT: rtl = 1.0; break;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix case Layout::RIGHT_TO_LEFT: rtl = -1.0; break;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix }
77a4a003111bd5cfb771d4849801c898aeb889b0cilix if(doUTN)oldtarget=SingleUnicodeToNon(*text_iter); // this should only ever be with a 1:1 glyph:character situation
77a4a003111bd5cfb771d4849801c898aeb889b0cilix
77a4a003111bd5cfb771d4849801c898aeb889b0cilix // accumulate a record to write
77a4a003111bd5cfb771d4849801c898aeb889b0cilix
77a4a003111bd5cfb771d4849801c898aeb889b0cilix unsigned lc_index = char_index;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix unsigned hold_iisi = _spans[span_index].in_input_stream_item;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix while(1){
77a4a003111bd5cfb771d4849801c898aeb889b0cilix glyph_index = _characters[lc_index].in_glyph;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix if(glyph_index == -1){ // end of a line within a paragraph, for instance
77a4a003111bd5cfb771d4849801c898aeb889b0cilix lc_index++;
23d859f2ce09c04ed802cb4912cc9c50f512f0a2bgk break;
97a20864afec63a0b7bb757b628ee2ae596cf648cilix }
97a20864afec63a0b7bb757b628ee2ae596cf648cilix
97a20864afec63a0b7bb757b628ee2ae596cf648cilix // always append if here
97a20864afec63a0b7bb757b628ee2ae596cf648cilix text_string += *text_iter;
97a20864afec63a0b7bb757b628ee2ae596cf648cilix
97a20864afec63a0b7bb757b628ee2ae596cf648cilix // figure out char widths, used by EMF, not currently used elsewhere
97a20864afec63a0b7bb757b628ee2ae596cf648cilix double cwidth;
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
77a4a003111bd5cfb771d4849801c898aeb889b0cilix }
77a4a003111bd5cfb771d4849801c898aeb889b0cilix else {
77a4a003111bd5cfb771d4849801c898aeb889b0cilix cwidth = 0;
77a4a003111bd5cfb771d4849801c898aeb889b0cilix }
77a4a003111bd5cfb771d4849801c898aeb889b0cilix char_x += cwidth;
2d2706a9d621c0da51b7c4178fd5c7c5e4765122joncruz/*
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
b802808a0226a87371021393c4f1da776aa6a6adjohanengelen*/
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if(ndx < MAX_DX){
b802808a0226a87371021393c4f1da776aa6a6adjohanengelen hold_dx[ndx++] = fabs(cwidth);
dda97aeba7480d08320ebceecae13b8531db1b81johanengelen }
a2fbdfc8e80d3d1845bf0d5df989726ae2ffd5bfjohanengelen else { // silently truncate any text line silly enough to be longer than MAX_DX
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm lc_index = _characters.size();
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm break;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
ecda720053ff791e35dae3c5c1177bc225b6cdf1johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
46c4893a7458eda6edcd064121bc000634af7a09johanengelen // conditions that prevent this character from joining the record
46c4893a7458eda6edcd064121bc000634af7a09johanengelen lc_index++;
46c4893a7458eda6edcd064121bc000634af7a09johanengelen if(lc_index >= _characters.size()) break; // nothing more to process, so it must be the end of the record
46c4893a7458eda6edcd064121bc000634af7a09johanengelen text_iter++;
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 if(span_index != next_span_index){
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.
46c4893a7458eda6edcd064121bc000634af7a09johanengelen */
46c4893a7458eda6edcd064121bc000634af7a09johanengelen/*
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*/
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 /*
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 */
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm span_index = next_span_index;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm text_iter = _spans[span_index].input_stream_first_character;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen }
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen // write it
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen sp_print_bind(ctx, glyph_matrix, 1.0);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
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
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);
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen free(smuggle_string);
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen sp_print_release(ctx);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm ndx=0;
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen char_index = lc_index;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
0fc5ce7045233dae7e15fdc86774370f1b1d73cbjohanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm#ifdef HAVE_CAIRO_PDF
0fc5ce7045233dae7e15fdc86774370f1b1d73cbjohanengelenvoid Layout::showGlyphs(CairoRenderContext *ctx) const
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen if (_input_stream.empty()) return;
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm bool clip_mode = false;//(ctx->getRenderMode() == CairoRenderContext::RENDER_MODE_CLIP);
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen std::vector<CairoGlyphInfo> glyphtext;
2d107ef9730aff3f4d776ae0c2f7d983e289ce02joncruz
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 glyph_index++;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm continue;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
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]);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Geom::Affine glyph_matrix;
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm if (clip_mode) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm Geom::PathVector const *pathv = span.font->PathVector(_glyphs[glyph_index].glyph);
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix if (pathv) {
73d455c08e8062e257dd052d2d690b9300434351cilix Geom::PathVector pathv_trans = (*pathv) * glyph_matrix;
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix SPStyle const *style = text_source->style;
73d455c08e8062e257dd052d2d690b9300434351cilix ctx->renderPathVector(pathv_trans, style, Geom::OptRect());
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix }
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix glyph_index++;
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix continue;
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix }
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix Geom::Affine font_matrix = glyph_matrix;
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix font_matrix[4] = 0;
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix font_matrix[5] = 0;
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix
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) {
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix char_index--;
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix span_iter++;
5be124ad592f5c71eca838ad2eaac9ffa953605fcilix }
73d455c08e8062e257dd052d2d690b9300434351cilix
73d455c08e8062e257dd052d2d690b9300434351cilix // try to output as many characters as possible in one go
73d455c08e8062e257dd052d2d690b9300434351cilix Glib::ustring span_string;
1e944d29efb206f5d0b5d1069cb098e22169d548cilix unsigned this_span_index = _characters[_glyphs[glyph_index].in_character].in_span;
79d46cc367c4181803d9a7a327b163643f23e8a7cilix unsigned int first_index = glyph_index;
1e944d29efb206f5d0b5d1069cb098e22169d548cilix glyphtext.clear();
79d46cc367c4181803d9a7a327b163643f23e8a7cilix do {
79d46cc367c4181803d9a7a327b163643f23e8a7cilix span_string += *span_iter;
1e944d29efb206f5d0b5d1069cb098e22169d548cilix span_iter++;
5ce8d034d9fe78f969629cfe65d1a2518f173ba9cilix
5ce8d034d9fe78f969629cfe65d1a2518f173ba9cilix unsigned same_character = _glyphs[glyph_index].in_character;
1e944d29efb206f5d0b5d1069cb098e22169d548cilix while (glyph_index < _glyphs.size() && _glyphs[glyph_index].in_character == same_character) {
1e944d29efb206f5d0b5d1069cb098e22169d548cilix if (glyph_index != first_index)
73d455c08e8062e257dd052d2d690b9300434351cilix _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
73d455c08e8062e257dd052d2d690b9300434351cilix
73d455c08e8062e257dd052d2d690b9300434351cilix CairoGlyphInfo info;
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix info.index = _glyphs[glyph_index].glyph;
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix // this is the translation for x,y-offset
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix info.x = glyph_matrix[4];
147c8e03bb214f85cd5906ddc6413c4293c4baa9cilix info.y = glyph_matrix[5];
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix glyphtext.push_back(info);
bb78cf2c3a2ee8ea2c98433128556847f03f5799cilix
bb78cf2c3a2ee8ea2c98433128556847f03f5799cilix glyph_index++;
147c8e03bb214f85cd5906ddc6413c4293c4baa9cilix }
bb78cf2c3a2ee8ea2c98433128556847f03f5799cilix } while (glyph_index < _glyphs.size()
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix && _path_fitted == NULL
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix && (font_matrix * glyph_matrix.inverse()).isIdentity()
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix && _characters[_glyphs[glyph_index].in_character].in_span == this_span_index);
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix
bb78cf2c3a2ee8ea2c98433128556847f03f5799cilix // remove vertical flip
732fb09f9c502000068a77667c3356cbbd5d39d5cilix Geom::Affine flip_matrix;
732fb09f9c502000068a77667c3356cbbd5d39d5cilix flip_matrix.setIdentity();
732fb09f9c502000068a77667c3356cbbd5d39d5cilix flip_matrix[3] = -1.0;
732fb09f9c502000068a77667c3356cbbd5d39d5cilix font_matrix = flip_matrix * font_matrix;
732fb09f9c502000068a77667c3356cbbd5d39d5cilix
732fb09f9c502000068a77667c3356cbbd5d39d5cilix SPStyle const *style = text_source->style;
732fb09f9c502000068a77667c3356cbbd5d39d5cilix float opacity = SP_SCALE24_TO_FLOAT(style->opacity.value);
732fb09f9c502000068a77667c3356cbbd5d39d5cilix
732fb09f9c502000068a77667c3356cbbd5d39d5cilix if (opacity != 1.0) {
732fb09f9c502000068a77667c3356cbbd5d39d5cilix ctx->pushState();
732fb09f9c502000068a77667c3356cbbd5d39d5cilix ctx->setStateForStyle(style);
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix ctx->pushLayer();
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix }
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix if (glyph_index - first_index > 0)
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix ctx->renderGlyphtext(span.font->pFont, font_matrix, glyphtext, style);
2d2706a9d621c0da51b7c4178fd5c7c5e4765122joncruz if (opacity != 1.0) {
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix ctx->popLayer();
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix ctx->popState();
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix }
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix }
04c99c338ffdc6e10cb6f5c18f6f06b3f555e8ebcilix}
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen#endif
73d455c08e8062e257dd052d2d690b9300434351cilix
73d455c08e8062e257dd052d2d690b9300434351cilix// these functions are for dumpAsText() only. No need to translate
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic char const *direction_to_text(Layout::Direction d)
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen{
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm switch (d) {
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen case Layout::LEFT_TO_RIGHT: return "ltr";
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen case Layout::RIGHT_TO_LEFT: return "rtl";
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen case Layout::TOP_TO_BOTTOM: return "ttb";
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen case Layout::BOTTOM_TO_TOP: return "btt";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen return "???";
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen}
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelenstatic char const *style_to_text(PangoStyle s)
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen{
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen switch (s) {
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen case PANGO_STYLE_NORMAL: return "upright";
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen case PANGO_STYLE_ITALIC: return "italic";
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen case PANGO_STYLE_OBLIQUE: return "oblique";
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm return "???";
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen}
c0cd5511d3b975ebe07d019c1f5528108725e438johanengelen
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmstatic char const *weight_to_text(PangoWeight w)
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm{
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm switch (w) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm case PANGO_WEIGHT_THIN : return "thin";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm case PANGO_WEIGHT_ULTRALIGHT: return "ultralight";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm case PANGO_WEIGHT_LIGHT : return "light";
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen case PANGO_WEIGHT_BOOK : return "book";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm case PANGO_WEIGHT_NORMAL : return "normalweight";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm case PANGO_WEIGHT_MEDIUM : return "medium";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm case PANGO_WEIGHT_SEMIBOLD : return "semibold";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm case PANGO_WEIGHT_BOLD : return "bold";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm case PANGO_WEIGHT_ULTRABOLD : return "ultrabold";
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen case PANGO_WEIGHT_HEAVY : return "heavy";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm case PANGO_WEIGHT_ULTRAHEAVY: return "ultraheavy";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm return "???";
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm}
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrmGlib::ustring Layout::getFontFamily(unsigned span_index) const
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen{
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen if (span_index >= _spans.size())
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen return "";
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen if (_spans[span_index].font) {
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen return sp_font_description_get_family(_spans[span_index].font->descr);
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen }
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen return "";
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen}
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelenGlib::ustring Layout::dumpAsText() const
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen{
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen Glib::ustring result;
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen char line[256];
93bb287e28a818fd5ba61b99d012e0500a49ccf6johanengelen
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen Glib::ustring::const_iterator icc;
56542e2b97ec8826cc692153b0e2d4f5ac8ef913johanengelen
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen snprintf(line, sizeof(line), "spans %d\n", _spans.size());
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen result += line;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen snprintf(line, sizeof(line), "chars %d\n", _characters.size());
af8d25189f88abf89cdbe0e180e271c94079624fbuliabyak result += line;
af8d25189f88abf89cdbe0e180e271c94079624fbuliabyak snprintf(line, sizeof(line), "glyphs %d\n", _glyphs.size());
af8d25189f88abf89cdbe0e180e271c94079624fbuliabyak result += line;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen unsigned lastspan=5000;
af8d25189f88abf89cdbe0e180e271c94079624fbuliabyak if(_characters.size() > 1){
a0334366488989ef25fb812d7030d298c0917c96johanengelen for(unsigned j = 0; j < _characters.size() ; j++){
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen if(lastspan != _characters[j].in_span){
a0334366488989ef25fb812d7030d298c0917c96johanengelen lastspan = _characters[j].in_span;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen icc = _spans[lastspan].input_stream_first_character;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen }
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);
a0334366488989ef25fb812d7030d298c0917c96johanengelen result += line;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen icc++;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen }
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen }
f9504c822b72a774b910958446fd1e730235b7cbjoncruz if(_glyphs.size()){
a0334366488989ef25fb812d7030d298c0917c96johanengelen for(unsigned j = 0; j < _glyphs.size() ; j++){
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 result += line;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen }
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen }
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen for (unsigned span_index = 0 ; span_index < _spans.size() ; span_index++) {
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen snprintf(line, sizeof(line), "==== span %d \n", span_index);
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen result += line;
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 result += line;
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 result += line;
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 result += line;
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);
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen result += line;
fb5a72174252e0e79107dcad3bf5a2bbd73e349cjohanengelen if (_spans[span_index].font) {
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 result += line;
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen }
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen snprintf(line, sizeof(line), " x_start = %f, x_end = %f\n", _spans[span_index].x_start, _spans[span_index].x_end);
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen result += line;
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 result += line;
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));
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen result += line;
42e99769805c14a5cc01c805faa3c3b03f9dd1c0johanengelen result += " ** characters:\n";
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 iter_char++;
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen }
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen result += line;
bdd7add6c064afee52d2eabeaa18f745430e5a4djohanengelen }
ddc251b3cf95b0097b6a5ee39ea132bd4d7d5cbcjohanengelen result += " ** glyphs:\n";
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);
42ba1b712b7b430669fc49aa9facb439181081becilix result += line;
42ba1b712b7b430669fc49aa9facb439181081becilix }
42ba1b712b7b430669fc49aa9facb439181081becilix result += "\n";
42ba1b712b7b430669fc49aa9facb439181081becilix }
42ba1b712b7b430669fc49aa9facb439181081becilix result += "EOT\n";
42ba1b712b7b430669fc49aa9facb439181081becilix return result;
42ba1b712b7b430669fc49aa9facb439181081becilix}
42ba1b712b7b430669fc49aa9facb439181081becilix
42ba1b712b7b430669fc49aa9facb439181081becilixvoid Layout::fitToPathAlign(SVGLength const &startOffset, Path const &path)
42ba1b712b7b430669fc49aa9facb439181081becilix{
42ba1b712b7b430669fc49aa9facb439181081becilix double offset = 0.0;
42ba1b712b7b430669fc49aa9facb439181081becilix
42ba1b712b7b430669fc49aa9facb439181081becilix if (startOffset._set) {
42ba1b712b7b430669fc49aa9facb439181081becilix if (startOffset.unit == SVGLength::PERCENT)
42ba1b712b7b430669fc49aa9facb439181081becilix offset = startOffset.computed * const_cast<Path&>(path).Length();
42ba1b712b7b430669fc49aa9facb439181081becilix else
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm offset = startOffset.computed;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm switch (_paragraphs.front().alignment) {
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm case CENTER:
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm offset -= _getChunkWidth(0) * 0.5;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm break;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm case RIGHT:
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm offset -= _getChunkWidth(0);
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm break;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm default:
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm break;
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm }
f07bfd5a05d43a6d11f7cd442f085149092dea88pjrm
if (_characters.empty()) {
int unused = 0;
Path::cut_position *point_otp = const_cast<Path&>(path).CurvilignToPosition(1, &offset, unused);
if (offset >= 0.0 && point_otp != NULL && point_otp[0].piece >= 0) {
Geom::Point point;
Geom::Point tangent;
const_cast<Path&>(path).PointAndTangentAt(point_otp[0].piece, point_otp[0].t, point, tangent);
_empty_cursor_shape.position = point;
if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) {
_empty_cursor_shape.rotation = atan2(-tangent[Geom::X], tangent[Geom::Y]);
} else {
_empty_cursor_shape.rotation = atan2(tangent[Geom::Y], tangent[Geom::X]);
}
}
}
for (unsigned char_index = 0 ; char_index < _characters.size() ; ) {
Span const &span = _characters[char_index].span(this);
size_t next_cluster_char_index = 0; // TODO refactor to not bump via for loops
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)
{
break;
}
}
size_t next_cluster_glyph_index = 0;
if (next_cluster_char_index == _characters.size()) {
next_cluster_glyph_index = _glyphs.size();
} else {
next_cluster_glyph_index = _characters[next_cluster_char_index].in_glyph;
}
double start_offset = offset + span.x_start + _characters[char_index].x;
double cluster_width = 0.0;
size_t const current_cluster_glyph_index = _characters[char_index].in_glyph;
for (size_t glyph_index = current_cluster_glyph_index ; glyph_index < next_cluster_glyph_index ; glyph_index++)
{
cluster_width += _glyphs[glyph_index].width;
}
// TODO block progression?
if (span.direction == RIGHT_TO_LEFT)
{
start_offset -= cluster_width;
}
double end_offset = start_offset + cluster_width;
int unused = 0;
double midpoint_offset = (start_offset + end_offset) * 0.5;
// as far as I know these functions are const, they're just not marked as such
Path::cut_position *midpoint_otp = const_cast<Path&>(path).CurvilignToPosition(1, &midpoint_offset, unused);
if (midpoint_offset >= 0.0 && midpoint_otp != NULL && midpoint_otp[0].piece >= 0) {
Geom::Point midpoint;
Geom::Point tangent;
const_cast<Path&>(path).PointAndTangentAt(midpoint_otp[0].piece, midpoint_otp[0].t, midpoint, tangent);
if (start_offset >= 0.0 && end_offset >= 0.0) {
Path::cut_position *start_otp = const_cast<Path&>(path).CurvilignToPosition(1, &start_offset, unused);
if (start_otp != NULL && start_otp[0].piece >= 0) {
Path::cut_position *end_otp = const_cast<Path&>(path).CurvilignToPosition(1, &end_offset, unused);
if (end_otp != NULL && end_otp[0].piece >= 0) {
bool on_same_subpath = true;
for (size_t i = 0 ; i < path.pts.size() ; i++) {
if (path.pts[i].piece <= start_otp[0].piece) continue;
if (path.pts[i].piece >= end_otp[0].piece) break;
if (path.pts[i].isMoveTo == polyline_moveto) {
on_same_subpath = false;
break;
}
}
if (on_same_subpath) {
// both points were on the same subpath (without this test the angle is very weird)
Geom::Point startpoint, endpoint;
const_cast<Path&>(path).PointAt(start_otp[0].piece, start_otp[0].t, startpoint);
const_cast<Path&>(path).PointAt(end_otp[0].piece, end_otp[0].t, endpoint);
if (endpoint != startpoint) {
tangent = endpoint - startpoint;
tangent.normalize();
} else {
tangent = Geom::Point (0,0);
}
}
g_free(end_otp);
}
g_free(start_otp);
}
}
if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) {
double rotation = atan2(-tangent[Geom::X], tangent[Geom::Y]);
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;
_glyphs[glyph_index].rotation += rotation;
}
} else {
double rotation = atan2(tangent[Geom::Y], tangent[Geom::X]);
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);
if (span.direction == RIGHT_TO_LEFT)
{
tangent_shift += cluster_width;
}
_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;
_glyphs[glyph_index].rotation += rotation;
}
}
_input_truncated = false;
} else { // outside the bounds of the path: hide the glyphs
_characters[char_index].in_glyph = -1;
_input_truncated = true;
}
g_free(midpoint_otp);
char_index = next_cluster_char_index;
}
for (unsigned span_index = 0 ; span_index < _spans.size() ; span_index++) {
_spans[span_index].x_start += offset;
_spans[span_index].x_end += offset;
}
_path_fitted = &path;
}
SPCurve *Layout::convertToCurves(iterator const &from_glyph, iterator const &to_glyph) const
{
GSList *cc = NULL;
for (int glyph_index = from_glyph._glyph_index ; glyph_index < to_glyph._glyph_index ; glyph_index++) {
Geom::Affine glyph_matrix;
Span const &span = _glyphs[glyph_index].span(this);
_getGlyphTransformMatrix(glyph_index, &glyph_matrix);
Geom::PathVector const * pathv = span.font->PathVector(_glyphs[glyph_index].glyph);
if (pathv) {
Geom::PathVector pathv_trans = (*pathv) * glyph_matrix;
SPCurve *c = new SPCurve(pathv_trans);
if (c) cc = g_slist_prepend(cc, c);
}
}
cc = g_slist_reverse(cc);
SPCurve *curve;
if ( cc ) {
curve = SPCurve::concat(cc);
} else {
curve = new SPCurve();
}
while (cc) {
/* fixme: This is dangerous, as we are mixing art_alloc and g_new */
reinterpret_cast<SPCurve *>(cc->data)->unref();
cc = g_slist_remove(cc, cc->data);
}
return curve;
}
void Layout::transform(Geom::Affine const &transform)
{
// this is all massively oversimplified
// I can't actually think of anybody who'll want to use it at the moment, so it'll stay simple
for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; glyph_index++) {
Geom::Point point(_glyphs[glyph_index].x, _glyphs[glyph_index].y);
point *= transform;
_glyphs[glyph_index].x = point[0];
_glyphs[glyph_index].y = point[1];
}
}
}//namespace Text
}//namespace Inkscape
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :