index 40bd71027f5f8b870b485facf0f010e2f8379a36..9ff953c47ba6ee0bf97b3cb44a117b9eca1aac77 100755 (executable)
#include "print.h"
#include "extension/print.h"
#include "livarot/Path.h"
+#include "libnr/nr-matrix-fns.h"
#include "libnr/nr-scale-matrix-ops.h"
#include "font-instance.h"
#include "svg/svg-length.h"
+#include "extension/internal/cairo-render-context.h"
+
+namespace Inkscape {
+ namespace Extension {
+ namespace Internal {
+ class CairoRenderContext;
+ class CairoGlyphInfo;
+ }
+ }
+}
+
+using Inkscape::Extension::Internal::CairoRenderContext;
+using Inkscape::Extension::Internal::CairoGlyphInfo;
namespace Inkscape {
namespace Text {
if (other.leading > leading) leading = other.leading;
}
-void Layout::_getGlyphTransformMatrix(int glyph_index, NRMatrix *matrix) const
+void Layout::_getGlyphTransformMatrix(int glyph_index, NR::Matrix *matrix) const
{
Span const &span = _glyphs[glyph_index].span(this);
double sin_rotation = sin(_glyphs[glyph_index].rotation);
nr_arena_glyphs_group_set_style(nr_group, text_source->style);
while (glyph_index < (int)_glyphs.size() && _characters[_glyphs[glyph_index].in_character].in_span == span_index) {
if (_characters[_glyphs[glyph_index].in_character].in_glyph != -1) {
- NRMatrix glyph_matrix;
+ NR::Matrix glyph_matrix;
_getGlyphTransformMatrix(glyph_index, &glyph_matrix);
nr_arena_glyphs_group_add_component(nr_group, _spans[span_index].font, _glyphs[glyph_index].glyph, &glyph_matrix);
}
@@ -95,30 +109,32 @@ void Layout::getBoundingBox(NRRect *bounding_box, NR::Matrix const &transform, i
if ((int) _glyphs[glyph_index].in_character > start + length) continue;
}
// this could be faster
- NRMatrix glyph_matrix;
+ NR::Matrix glyph_matrix;
_getGlyphTransformMatrix(glyph_index, &glyph_matrix);
NR::Matrix total_transform = glyph_matrix;
total_transform *= transform;
- NR::Rect glyph_rect = _glyphs[glyph_index].span(this).font->BBox(_glyphs[glyph_index].glyph);
- NR::Point bmi = glyph_rect.min(), bma = glyph_rect.max();
- NR::Point tlp(bmi[0],bmi[1]), trp(bma[0],bmi[1]), blp(bmi[0],bma[1]), brp(bma[0],bma[1]);
- tlp *= total_transform;
- trp *= total_transform;
- blp *= total_transform;
- brp *= total_transform;
- glyph_rect = NR::Rect(tlp,trp);
- glyph_rect.expandTo(blp);
- glyph_rect.expandTo(brp);
- if ( (glyph_rect.min())[0] < bounding_box->x0 ) bounding_box->x0=(glyph_rect.min())[0];
- if ( (glyph_rect.max())[0] > bounding_box->x1 ) bounding_box->x1=(glyph_rect.max())[0];
- if ( (glyph_rect.min())[1] < bounding_box->y0 ) bounding_box->y0=(glyph_rect.min())[1];
- if ( (glyph_rect.max())[1] > bounding_box->y1 ) bounding_box->y1=(glyph_rect.max())[1];
+ NR::Maybe<NR::Rect> glyph_rect = _glyphs[glyph_index].span(this).font->BBox(_glyphs[glyph_index].glyph);
+ if (glyph_rect) {
+ NR::Point bmi = glyph_rect->min(), bma = glyph_rect->max();
+ NR::Point tlp(bmi[0],bmi[1]), trp(bma[0],bmi[1]), blp(bmi[0],bma[1]), brp(bma[0],bma[1]);
+ tlp *= total_transform;
+ trp *= total_transform;
+ blp *= total_transform;
+ brp *= total_transform;
+ *glyph_rect = NR::Rect(tlp,trp);
+ glyph_rect->expandTo(blp);
+ glyph_rect->expandTo(brp);
+ if ( (glyph_rect->min())[0] < bounding_box->x0 ) bounding_box->x0=(glyph_rect->min())[0];
+ if ( (glyph_rect->max())[0] > bounding_box->x1 ) bounding_box->x1=(glyph_rect->max())[0];
+ if ( (glyph_rect->min())[1] < bounding_box->y0 ) bounding_box->y0=(glyph_rect->min())[1];
+ if ( (glyph_rect->max())[1] > bounding_box->y1 ) bounding_box->y1=(glyph_rect->max())[1];
+ }
}
}
void Layout::print(SPPrintContext *ctx,
NRRect const *pbox, NRRect const *dbox, NRRect const *bbox,
- NRMatrix const &ctm) const
+ NR::Matrix const &ctm) const
{
if (_input_stream.empty()) return;
glyph_index++;
continue;
}
- NRMatrix glyph_matrix;
+ NR::Matrix glyph_matrix;
Span const &span = _spans[_characters[_glyphs[glyph_index].in_character].in_span];
InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[span.in_input_stream_item]);
if (text_to_path || _path_fitted) {
NRBPath abp;
_getGlyphTransformMatrix(glyph_index, &glyph_matrix);
abp.path = nr_artpath_affine(bpath.path, glyph_matrix);
- if (text_source->style->fill.type != SP_PAINT_TYPE_NONE)
+ if (!text_source->style->fill.isNone())
sp_print_fill(ctx, &abp, &ctm, text_source->style, pbox, dbox, bbox);
- if (text_source->style->stroke.type != SP_PAINT_TYPE_NONE)
+ if (!text_source->style->stroke.isNone())
sp_print_stroke(ctx, &abp, &ctm, text_source->style, pbox, dbox, bbox);
g_free(abp.path);
}
NR::Point g_pos(0,0); // all strings are output at (0,0) because we do the translation using the matrix
glyph_matrix = NR::Matrix(NR::scale(1.0, -1.0) * NR::Matrix(NR::rotate(_glyphs[glyph_index].rotation)));
if (block_progression == LEFT_TO_RIGHT || block_progression == RIGHT_TO_LEFT) {
- glyph_matrix.c[4] = span.line(this).baseline_y + span.baseline_shift;
+ glyph_matrix[4] = span.line(this).baseline_y + span.baseline_shift;
// since we're outputting character codes, not glyphs, we want the character x
- glyph_matrix.c[5] = span.chunk(this).left_x + span.x_start + _characters[_glyphs[glyph_index].in_character].x;
+ glyph_matrix[5] = span.chunk(this).left_x + span.x_start + _characters[_glyphs[glyph_index].in_character].x;
} else {
- glyph_matrix.c[4] = span.chunk(this).left_x + span.x_start + _characters[_glyphs[glyph_index].in_character].x;
- glyph_matrix.c[5] = span.line(this).baseline_y + span.baseline_shift;
+ glyph_matrix[4] = span.chunk(this).left_x + span.x_start + _characters[_glyphs[glyph_index].in_character].x;
+ glyph_matrix[5] = span.line(this).baseline_y + span.baseline_shift;
}
Glib::ustring::const_iterator span_iter = span.input_stream_first_character;
unsigned char_index = _glyphs[glyph_index].in_character;
}
}
+#ifdef HAVE_CAIRO_PDF
+void Layout::showGlyphs(CairoRenderContext *ctx) const
+{
+ if (_input_stream.empty()) return;
+
+ bool clip_mode = false;//(ctx->getRenderMode() == CairoRenderContext::RENDER_MODE_CLIP);
+ std::vector<CairoGlyphInfo> glyphtext;
+
+ for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; ) {
+ if (_characters[_glyphs[glyph_index].in_character].in_glyph == -1) {
+ // invisible glyphs
+ unsigned same_character = _glyphs[glyph_index].in_character;
+ while (_glyphs[glyph_index].in_character == same_character)
+ glyph_index++;
+ continue;
+ }
+ Span const &span = _spans[_characters[_glyphs[glyph_index].in_character].in_span];
+ InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[span.in_input_stream_item]);
+
+ NR::Matrix glyph_matrix;
+ _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
+ if (clip_mode) {
+ NArtBpath *bpath = (NArtBpath*)span.font->ArtBPath(_glyphs[glyph_index].glyph);
+ if (bpath) {
+ NArtBpath *abp = nr_artpath_affine(bpath, glyph_matrix);
+ NRBPath bpath;
+ bpath.path = abp;
+ SPStyle const *style = text_source->style;
+ ctx->renderPath(&bpath, style, NULL);
+ g_free(abp);
+ }
+ glyph_index++;
+ continue;
+ }
+
+ NR::Matrix font_matrix;
+ if (_path_fitted == NULL) {
+ font_matrix = glyph_matrix;
+ font_matrix[4] = 0;
+ font_matrix[5] = 0;
+ } else {
+ font_matrix.set_identity();
+ }
+
+ Glib::ustring::const_iterator span_iter = span.input_stream_first_character;
+ unsigned char_index = _glyphs[glyph_index].in_character;
+ unsigned original_span = _characters[char_index].in_span;
+ while (char_index && _characters[char_index - 1].in_span == original_span) {
+ char_index--;
+ span_iter++;
+ }
+
+ // try to output as many characters as possible in one go
+ Glib::ustring span_string;
+ unsigned this_span_index = _characters[_glyphs[glyph_index].in_character].in_span;
+ unsigned int first_index = glyph_index;
+ glyphtext.clear();
+ do {
+ span_string += *span_iter;
+ span_iter++;
+
+ unsigned same_character = _glyphs[glyph_index].in_character;
+ while (glyph_index < _glyphs.size() && _glyphs[glyph_index].in_character == same_character) {
+ if (glyph_index != first_index)
+ _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
+
+ CairoGlyphInfo info;
+ info.index = _glyphs[glyph_index].glyph;
+ if (_path_fitted == NULL) {
+ info.x = glyph_matrix[4];
+ info.y = glyph_matrix[5];
+ } else {
+ info.x = 0;
+ info.y = 0;
+ }
+ glyphtext.push_back(info);
+
+ glyph_index++;
+ }
+ } while (glyph_index < _glyphs.size()
+ && _path_fitted == NULL
+ && NR::transform_equalp(font_matrix, glyph_matrix, NR_EPSILON)
+ && _characters[_glyphs[glyph_index].in_character].in_span == this_span_index);
+
+ // remove vertical flip
+ font_matrix[3] *= -1.0;
+
+ SPStyle const *style = text_source->style;
+ float opacity = SP_SCALE24_TO_FLOAT(style->opacity.value);
+
+ if (_path_fitted) {
+ ctx->pushState();
+ ctx->transform(&glyph_matrix);
+ } else if (opacity != 1.0) {
+ ctx->pushState();
+ ctx->setStateForStyle(style);
+ ctx->pushLayer();
+ }
+ if (glyph_index - first_index > 0)
+ ctx->renderGlyphtext(span.font->pFont, &font_matrix, glyphtext, style);
+ if (_path_fitted)
+ ctx->popState();
+ else if (opacity != 1.0) {
+ ctx->popLayer();
+ ctx->popState();
+ }
+ }
+}
+#endif
+
// these functions are for dumpAsText() only. No need to translate
static char const *direction_to_text(Layout::Direction d)
{
@@ -418,7 +544,7 @@ SPCurve *Layout::convertToCurves(iterator const &from_glyph, iterator const &to_
GSList *cc = NULL;
for (int glyph_index = from_glyph._glyph_index ; glyph_index < to_glyph._glyph_index ; glyph_index++) {
- NRMatrix glyph_matrix;
+ NR::Matrix glyph_matrix;
Span const &span = _glyphs[glyph_index].span(this);
_getGlyphTransformMatrix(glyph_index, &glyph_matrix);