X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Flibnrtype%2FLayout-TNG-Output.cpp;h=f34b93d6efaad7da92f85e0ae65c96d3d2fdcd8f;hb=c1bec19e42abed2d215058d26b0132b5173632c2;hp=08eb403db972d1908948f07a65d1e8ff06aa80ae;hpb=6b15695578f07a3f72c4c9475c1a261a3021472a;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 08eb403db..f34b93d6e --- a/src/libnrtype/Layout-TNG-Output.cpp +++ b/src/libnrtype/Layout-TNG-Output.cpp @@ -8,15 +8,40 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ +#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> + +#if !PANGO_VERSION_CHECK(1,24,0) +#define PANGO_WEIGHT_THIN static_cast(100) +#define PANGO_WEIGHT_BOOK static_cast(380) +#define PANGO_WEIGHT_MEDIUM static_cast(500) +#define PANGO_WEIGHT_ULTRAHEAVY static_cast(1000) +#endif + +namespace Inkscape { + namespace Extension { + namespace Internal { + class CairoRenderContext; + class CairoGlyphInfo; + } + } +} + +using Inkscape::Extension::Internal::CairoRenderContext; +using Inkscape::Extension::Internal::CairoGlyphInfo; namespace Inkscape { namespace Text { @@ -41,7 +66,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, Geom::Matrix *matrix) const { Span const &span = _glyphs[glyph_index].span(this); double sin_rotation = sin(_glyphs[glyph_index].rotation); @@ -72,9 +97,9 @@ 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; + Geom::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); + nr_arena_glyphs_group_add_component(nr_group, _spans[span_index].font, _glyphs[glyph_index].glyph, glyph_matrix); } glyph_index++; } @@ -83,38 +108,49 @@ void Layout::show(NRArenaGroup *in_arena, NRRect const *paintbox) const nr_arena_item_request_update(NR_ARENA_ITEM(in_arena), NR_ARENA_ITEM_STATE_ALL, FALSE); } -void Layout::getBoundingBox(NRRect *bounding_box, NR::Matrix const &transform) const +void Layout::getBoundingBox(NRRect *bounding_box, Geom::Matrix const &transform, int start, int length) const { for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; glyph_index++) { if (_characters[_glyphs[glyph_index].in_character].in_glyph == -1) continue; + if (start != -1 && (int) _glyphs[glyph_index].in_character < start) continue; + if (length != -1) { + if (start == -1) + start = 0; + if ((int) _glyphs[glyph_index].in_character > start + length) continue; + } // this could be faster - NRMatrix glyph_matrix; + Geom::Matrix glyph_matrix; _getGlyphTransformMatrix(glyph_index, &glyph_matrix); - NR::Matrix total_transform = glyph_matrix; + Geom::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]; + if(_glyphs[glyph_index].span(this).font) { + Geom::OptRect glyph_rect = _glyphs[glyph_index].span(this).font->BBox(_glyphs[glyph_index].glyph); + if (glyph_rect) { + Geom::Point bmi = glyph_rect->min(), bma = glyph_rect->max(); + Geom::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 = Geom::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 + Geom::Matrix const &ctm) const { if (_input_stream.empty()) return; + Geom::Matrix ctm_2geom(ctm); Direction block_progression = _blockProgression(); bool text_to_path = ctx->module->textToPath(); for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; ) { @@ -125,33 +161,30 @@ void Layout::print(SPPrintContext *ctx, glyph_index++; continue; } - NRMatrix glyph_matrix; + Geom::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); - nr_free(abp.path); + Geom::PathVector temp_pv = (*pv) * glyph_matrix; + if (!text_source->style->fill.isNone()) + sp_print_fill(ctx, temp_pv, &ctm_2geom, text_source->style, pbox, dbox, bbox); + if (!text_source->style->stroke.isNone()) + sp_print_stroke(ctx, temp_pv, &ctm_2geom, 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))); + Geom::Point g_pos(0,0); // all strings are output at (0,0) because we do the translation using the matrix + glyph_matrix = Geom::Scale(1.0, -1.0) * (Geom::Matrix)Geom::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; @@ -185,6 +218,103 @@ 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]); + + Geom::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) * glyph_matrix; + SPStyle const *style = text_source->style; + ctx->renderPathVector(pathv_trans, style, NULL); + } + glyph_index++; + continue; + } + + Geom::Matrix font_matrix = glyph_matrix; + font_matrix[4] = 0; + font_matrix[5] = 0; + + 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; + // this is the translation for x,y-offset + info.x = glyph_matrix[4]; + info.y = glyph_matrix[5]; + + 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 + Geom::Matrix flip_matrix; + flip_matrix.setIdentity(); + flip_matrix[3] = -1.0; + font_matrix = flip_matrix * font_matrix; + + SPStyle const *style = text_source->style; + float opacity = SP_SCALE24_TO_FLOAT(style->opacity.value); + + 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 (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) { @@ -210,13 +340,17 @@ static char const *style_to_text(PangoStyle s) static char const *weight_to_text(PangoWeight w) { switch (w) { + case PANGO_WEIGHT_THIN : return "thin"; case PANGO_WEIGHT_ULTRALIGHT: return "ultralight"; case PANGO_WEIGHT_LIGHT : return "light"; - case PANGO_WEIGHT_SEMIBOLD : return "semibold"; + case PANGO_WEIGHT_BOOK : return "book"; case PANGO_WEIGHT_NORMAL : return "normalweight"; + case PANGO_WEIGHT_MEDIUM : return "medium"; + case PANGO_WEIGHT_SEMIBOLD : return "semibold"; case PANGO_WEIGHT_BOLD : return "bold"; case PANGO_WEIGHT_ULTRABOLD : return "ultrabold"; case PANGO_WEIGHT_HEAVY : return "heavy"; + case PANGO_WEIGHT_ULTRAHEAVY: return "ultraheavy"; } return "???"; } @@ -303,11 +437,11 @@ void Layout::fitToPathAlign(SVGLength const &startOffset, Path const &path) int unused = 0; Path::cut_position *point_otp = const_cast(path).CurvilignToPosition(1, &offset, unused); if (offset >= 0.0 && point_otp != NULL && point_otp[0].piece >= 0) { - NR::Point point; - NR::Point tangent; + Geom::Point point; + Geom::Point tangent; const_cast(path).PointAndTangentAt(point_otp[0].piece, point_otp[0].t, point, tangent); _empty_cursor_shape.position = point; - _empty_cursor_shape.rotation = atan2(tangent[NR::Y], tangent[NR::X]); + _empty_cursor_shape.rotation = atan2(tangent[Geom::Y], tangent[Geom::X]); } } @@ -317,9 +451,10 @@ void Layout::fitToPathAlign(SVGLength const &startOffset, Path const &path) double character_advance; Span const &span = _characters[char_index].span(this); - for (next_cluster_char_index = char_index + 1 ; - next_cluster_char_index < _characters.size() && !_characters[next_cluster_char_index].char_attributes.is_cursor_position; - next_cluster_char_index++); + 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; + } if (next_cluster_char_index == _characters.size()) { next_cluster_glyph_index = _glyphs.size(); @@ -343,9 +478,8 @@ void Layout::fitToPathAlign(SVGLength const &startOffset, Path const &path) // as far as I know these functions are const, they're just not marked as such Path::cut_position *midpoint_otp = const_cast(path).CurvilignToPosition(1, &midpoint_offset, unused); if (midpoint_offset >= 0.0 && midpoint_otp != NULL && midpoint_otp[0].piece >= 0) { - NR::Point midpoint; - NR::Point tangent; - + Geom::Point midpoint; + Geom::Point tangent; const_cast(path).PointAndTangentAt(midpoint_otp[0].piece, midpoint_otp[0].t, midpoint, tangent); if (start_offset >= 0.0 && end_offset >= 0.0) { @@ -364,14 +498,14 @@ void Layout::fitToPathAlign(SVGLength const &startOffset, Path const &path) } if (on_same_subpath) { // both points were on the same subpath (without this test the angle is very weird) - NR::Point startpoint, endpoint; + Geom::Point startpoint, endpoint; const_cast(path).PointAt(start_otp[0].piece, start_otp[0].t, startpoint); const_cast(path).PointAt(end_otp[0].piece, end_otp[0].t, endpoint); if (endpoint != startpoint) { tangent = endpoint - startpoint; tangent.normalize(); } else { - tangent = NR::Point (0,0); + tangent = Geom::Point (0,0); } } g_free(end_otp); @@ -390,8 +524,10 @@ void Layout::fitToPathAlign(SVGLength const &startOffset, Path const &path) _glyphs[glyph_index].y = midpoint[1] - _lines.front().baseline_y + tangent[1] * tangent_shift + tangent[0] * normal_shift; _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); @@ -411,15 +547,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; + Geom::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) * glyph_matrix; + SPCurve *c = new SPCurve(pathv_trans); if (c) cc = g_slist_prepend(cc, c); } } @@ -427,26 +562,26 @@ 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); } return curve; } -void Layout::transform(NR::Matrix const &transform) +void Layout::transform(Geom::Matrix 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++) { - NR::Point point(_glyphs[glyph_index].x, _glyphs[glyph_index].y); + 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];