X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Flibnrtype%2FLayout-TNG-Output.cpp;h=36c882d446d3a0b1b530b1d25dbb49c19fcf5c43;hb=8b9a820756fdf348239872236be2257f854e094a;hp=97d98d3c4a94f5acd4029ebe838b001fc1c6ac40;hpb=077a96a2caf396b77c44d2746903e01049f7777e;p=inkscape.git diff --git a/src/libnrtype/Layout-TNG-Output.cpp b/src/libnrtype/Layout-TNG-Output.cpp old mode 100755 new mode 100644 index 97d98d3c4..36c882d44 --- a/src/libnrtype/Layout-TNG-Output.cpp +++ b/src/libnrtype/Layout-TNG-Output.cpp @@ -9,16 +9,32 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ #include -#include #include "Layout-TNG.h" #include "display/nr-arena-glyphs.h" #include "style.h" #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 "libnr/nr-convert2geom.h" #include "font-instance.h" #include "svg/svg-length.h" +#include "extension/internal/cairo-render-context.h" +#include "display/curve.h" +#include <2geom/pathvector.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 { @@ -43,7 +59,7 @@ void Layout::LineHeight::max(LineHeight const &other) 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); @@ -74,7 +90,7 @@ void Layout::show(NRArenaGroup *in_arena, NRRect const *paintbox) const 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); } @@ -96,30 +112,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]; + boost::optional 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; @@ -133,33 +151,30 @@ void Layout::print(SPPrintContext *ctx, 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(_input_stream[span.in_input_stream_item]); if (text_to_path || _path_fitted) { - NRBPath bpath; - bpath.path = (NArtBpath*)span.font->ArtBPath(_glyphs[glyph_index].glyph); - if (bpath.path) { - NRBPath abp; + Geom::PathVector const * pv = span.font->PathVector(_glyphs[glyph_index].glyph); + if (pv) { _getGlyphTransformMatrix(glyph_index, &glyph_matrix); - abp.path = nr_artpath_affine(bpath.path, glyph_matrix); - if (text_source->style->fill.type != SP_PAINT_TYPE_NONE) - sp_print_fill(ctx, &abp, &ctm, text_source->style, pbox, dbox, bbox); - if (text_source->style->stroke.type != SP_PAINT_TYPE_NONE) - sp_print_stroke(ctx, &abp, &ctm, text_source->style, pbox, dbox, bbox); - g_free(abp.path); + Geom::PathVector temp_pv = (*pv) * to_2geom(glyph_matrix); + if (!text_source->style->fill.isNone()) + sp_print_fill(ctx, temp_pv, &ctm, text_source->style, pbox, dbox, bbox); + if (!text_source->style->stroke.isNone()) + sp_print_stroke(ctx, temp_pv, &ctm, text_source->style, pbox, dbox, bbox); } glyph_index++; } else { 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; @@ -193,6 +208,113 @@ void Layout::print(SPPrintContext *ctx, } } +#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 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(_input_stream[span.in_input_stream_item]); + + NR::Matrix glyph_matrix; + _getGlyphTransformMatrix(glyph_index, &glyph_matrix); + if (clip_mode) { + Geom::PathVector const *pathv = span.font->PathVector(_glyphs[glyph_index].glyph); + if (pathv) { + Geom::PathVector pathv_trans = (*pathv) * to_2geom(glyph_matrix); + SPStyle const *style = text_source->style; + ctx->renderPathVector(pathv_trans, style, NULL); + } + 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) { @@ -220,9 +342,7 @@ static char const *weight_to_text(PangoWeight w) switch (w) { case PANGO_WEIGHT_ULTRALIGHT: return "ultralight"; case PANGO_WEIGHT_LIGHT : return "light"; -#if GTK_CHECK_VERSION(2,6,0) case PANGO_WEIGHT_SEMIBOLD : return "semibold"; -#endif case PANGO_WEIGHT_NORMAL : return "normalweight"; case PANGO_WEIGHT_BOLD : return "bold"; case PANGO_WEIGHT_ULTRABOLD : return "ultrabold"; @@ -421,15 +541,14 @@ 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); - NRBPath bpath; - bpath.path = (NArtBpath*)span.font->ArtBPath(_glyphs[glyph_index].glyph); - if (bpath.path) { - NArtBpath *abp = nr_artpath_affine(bpath.path, glyph_matrix); - SPCurve *c = sp_curve_new_from_bpath(abp); + Geom::PathVector const * pathv = span.font->PathVector(_glyphs[glyph_index].glyph); + if (pathv) { + Geom::PathVector pathv_trans = (*pathv) * to_2geom(glyph_matrix); + SPCurve *c = new SPCurve(pathv_trans); if (c) cc = g_slist_prepend(cc, c); } } @@ -437,14 +556,14 @@ SPCurve *Layout::convertToCurves(iterator const &from_glyph, iterator const &to_ SPCurve *curve; if ( cc ) { - curve = sp_curve_concat(cc); + curve = SPCurve::concat(cc); } else { - curve = sp_curve_new(); + curve = new SPCurve(); } while (cc) { /* fixme: This is dangerous, as we are mixing art_alloc and g_new */ - sp_curve_unref((SPCurve *) cc->data); + reinterpret_cast(cc->data)->unref(); cc = g_slist_remove(cc, cc->data); }