Code

Correct #endif placement. Should fix win32 build.
[inkscape.git] / src / libnrtype / Layout-TNG-Output.cpp
index 499a8f7a5e83506f1068ec8e0b1ccfa61829becc..f34b93d6efaad7da92f85e0ae65c96d3d2fdcd8f 100644 (file)
 #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<PangoWeight>(100)
+#define PANGO_WEIGHT_BOOK       static_cast<PangoWeight>(380)
+#define PANGO_WEIGHT_MEDIUM     static_cast<PangoWeight>(500)
+#define PANGO_WEIGHT_ULTRAHEAVY static_cast<PangoWeight>(1000)
+#endif
 
 namespace Inkscape {
     namespace Extension {
@@ -57,7 +66,7 @@ void Layout::LineHeight::max(LineHeight const &other)
     if (other.leading > leading) leading = other.leading;
 }
 
-void Layout::_getGlyphTransformMatrix(int glyph_index, NR::Matrix *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);
@@ -88,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) {
-                NR::Matrix 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++;
         }
@@ -99,7 +108,7 @@ 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, int start, int length) 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;
@@ -110,35 +119,38 @@ 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
-        NR::Matrix 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::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];
+        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,
-                   NR::Matrix 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() ; ) {
@@ -149,27 +161,23 @@ void Layout::print(SPPrintContext *ctx,
                 glyph_index++;
             continue;
         }
-        NR::Matrix glyph_matrix;
+        Geom::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 bpath;
-            bpath.path = (NArtBpath*)span.font->ArtBPath(_glyphs[glyph_index].glyph);
-            if (bpath.path) {
-                const_NRBPath abp;
+            Geom::PathVector const * pv = span.font->PathVector(_glyphs[glyph_index].glyph);
+            if (pv) {
                 _getGlyphTransformMatrix(glyph_index, &glyph_matrix);
-                NArtBpath *temp_bpath = nr_artpath_affine(bpath.path, glyph_matrix);
-                abp.path = temp_bpath;
+                Geom::PathVector temp_pv = (*pv) * glyph_matrix;
                 if (!text_source->style->fill.isNone())
-                    sp_print_fill(ctx, &abp, &ctm, text_source->style, pbox, dbox, bbox);
+                    sp_print_fill(ctx, temp_pv, &ctm_2geom, text_source->style, pbox, dbox, bbox);
                 if (!text_source->style->stroke.isNone())
-                    sp_print_stroke(ctx, &abp, &ctm, text_source->style, pbox, dbox, bbox);
-                g_free(temp_bpath);
+                    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[4] = span.line(this).baseline_y + span.baseline_shift;
                 // since we're outputting character codes, not glyphs, we want the character x
@@ -214,7 +222,7 @@ void Layout::print(SPPrintContext *ctx,
 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;
 
@@ -229,30 +237,22 @@ void Layout::showGlyphs(CairoRenderContext *ctx) const
         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;
+        Geom::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);
-                const_NRBPath bpath;
-                bpath.path = abp;
+            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->renderPath(&bpath, style, NULL);
-                g_free(abp);
+                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();
-        }
+        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;
@@ -278,13 +278,10 @@ void Layout::showGlyphs(CairoRenderContext *ctx) const
 
                 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;                    
-                }
+                // this is the translation for x,y-offset
+                info.x = glyph_matrix[4];
+                info.y = glyph_matrix[5];
+
                 glyphtext.push_back(info);
 
                 glyph_index++;
@@ -293,26 +290,24 @@ void Layout::showGlyphs(CairoRenderContext *ctx) const
                  && _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;
+        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 (_path_fitted) {
-            ctx->pushState();
-            ctx->transform(&glyph_matrix);
-        } else if (opacity != 1.0) {
+
+        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) {
+        if (opacity != 1.0) {
             ctx->popLayer();
             ctx->popState();
         }
@@ -345,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 "???";
 }
@@ -438,11 +437,11 @@ void Layout::fitToPathAlign(SVGLength const &startOffset, Path const &path)
         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) {
-            NR::Point point;
-            NR::Point tangent;
+            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;
-            _empty_cursor_shape.rotation = atan2(tangent[NR::Y], tangent[NR::X]);
+            _empty_cursor_shape.rotation = atan2(tangent[Geom::Y], tangent[Geom::X]);
         }
     }
 
@@ -452,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();
@@ -478,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&>(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&>(path).PointAndTangentAt(midpoint_otp[0].piece, midpoint_otp[0].t, midpoint, tangent);
 
             if (start_offset >= 0.0 && end_offset >= 0.0) {
@@ -499,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&>(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 = NR::Point (0,0);
+                                tangent = Geom::Point (0,0);
                             }
                         }
                         g_free(end_otp);
@@ -525,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);
 
@@ -546,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++) {
-        NR::Matrix 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 = SPCurve::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);
         }
     }
@@ -576,12 +576,12 @@ SPCurve *Layout::convertToCurves(iterator const &from_glyph, iterator const &to_
     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];