Vector-based text rendering 84/56484/21
authorPaul Wisbey <p.wisbey@samsung.com>
Fri, 27 Nov 2015 15:28:55 +0000 (15:28 +0000)
committerPaul Wisbey <p.wisbey@samsung.com>
Wed, 20 Apr 2016 17:49:19 +0000 (10:49 -0700)
Change-Id: I1919a3fc7bddf399927d4ffc082af716b9f1032f

23 files changed:
build/tizen/adaptor/Makefile.am
build/tizen/adaptor/configure.ac
text/dali/devel-api/text-abstraction/font-client.cpp
text/dali/devel-api/text-abstraction/font-client.h
text/dali/devel-api/text-abstraction/text-abstraction-definitions.h
text/dali/internal/glyphy/file.list [new file with mode: 0644]
text/dali/internal/glyphy/glyphy-arc-bezier.hh [new file with mode: 0644]
text/dali/internal/glyphy/glyphy-arcs-bezier.hh [new file with mode: 0644]
text/dali/internal/glyphy/glyphy-arcs.cc [new file with mode: 0644]
text/dali/internal/glyphy/glyphy-blob-impl.cc [new file with mode: 0644]
text/dali/internal/glyphy/glyphy-common.hh [new file with mode: 0644]
text/dali/internal/glyphy/glyphy-extents.cc [new file with mode: 0644]
text/dali/internal/glyphy/glyphy-freetype.h [new file with mode: 0644]
text/dali/internal/glyphy/glyphy-geometry.hh [new file with mode: 0644]
text/dali/internal/glyphy/glyphy-outline.cc [new file with mode: 0644]
text/dali/internal/glyphy/glyphy-sdf.cc [new file with mode: 0644]
text/dali/internal/glyphy/glyphy.h [new file with mode: 0644]
text/dali/internal/glyphy/vector-font-cache.cpp [new file with mode: 0644]
text/dali/internal/glyphy/vector-font-cache.h [new file with mode: 0644]
text/dali/internal/text-abstraction/font-client-impl.cpp
text/dali/internal/text-abstraction/font-client-impl.h
text/dali/internal/text-abstraction/font-client-plugin-impl.cpp
text/dali/internal/text-abstraction/font-client-plugin-impl.h

index 6bca851..3d0c959 100644 (file)
@@ -101,6 +101,9 @@ include ../../../adaptors/devel-api/file.list
 static_libraries_libunibreak_src_dir = ../../../text/dali/internal/libunibreak
 include ../../../text/dali/internal/libunibreak/file.list
 
+static_libraries_glyphy_src_dir = ../../../text/dali/internal/glyphy
+include ../../../text/dali/internal/glyphy/file.list
+
 # Package doc
 package_doxy_dir = ../../../doc
 include ../../../doc/file.list
@@ -245,7 +248,10 @@ main_loop_integration_src_files = $(adaptor_common_internal_ecore_src_files)
 input_event_handler_src_files = $(adaptor_ecore_x_event_handler_internal_src_files)
 endif
 
-
+if ENABLE_VECTOR_BASED_TEXT_RENDERING
+adaptor_internal_src_files += $(static_libraries_glyphy_src_files)
+DALI_ADAPTOR_CFLAGS += -DENABLE_VECTOR_BASED_TEXT_RENDERING
+endif
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = dali-adaptor.pc dali-adaptor-integration.pc
index 7fee548..a415c13 100644 (file)
@@ -198,6 +198,9 @@ AM_CONDITIONAL([WAYLAND], [test x$enable_wayland = xyes])
 AM_CONDITIONAL([USE_EFL], [test x$enable_efl = xyes])
 AM_CONDITIONAL([USE_APPFW], [test x$enable_appfw = xyes])
 
+# Platforms with highp shader support can use vector based text
+AM_CONDITIONAL([ENABLE_VECTOR_BASED_TEXT_RENDERING], [test x$enable_profile = xUBUNTU])
+
 AM_CONDITIONAL([ENABLE_NETWORK_LOGGING], [test x$enable_networklogging = xyes])
 
 # Platforms should either enable features or remove them, they
index 414c45c..3460dff 100644 (file)
@@ -148,9 +148,9 @@ GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
   return GetImplementation(*this).GetGlyphIndex( fontId, charcode );
 }
 
-bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal, int desiredFixedSize )
+bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal, int desiredFixedSize )
 {
-  return GetImplementation(*this).GetGlyphMetrics( array, size, horizontal, desiredFixedSize );
+  return GetImplementation(*this).GetGlyphMetrics( array, size, type, horizontal, desiredFixedSize );
 }
 
 BufferImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
@@ -158,6 +158,11 @@ BufferImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
   return GetImplementation(*this).CreateBitmap( fontId, glyphIndex );
 }
 
+void FontClient::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
+{
+  GetImplementation(*this).CreateVectorBlob( fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
+}
+
 const GlyphInfo& FontClient::GetEllipsisGlyph( PointSize26Dot6 pointSize )
 {
   return GetImplementation(*this).GetEllipsisGlyph( pointSize );
index a1ffcb5..2614cfc 100644 (file)
@@ -290,14 +290,15 @@ public:
    * It may contain the advance and an offset set into the bearing from the shaping tool.
    * On return, the glyph's size value will be initialized. The bearing value will be updated by adding the font's glyph bearing to the one set by the shaping tool.
    * @param[in] size The size of the array.
+   * @param[in] type The type of glyphs used for rendering; either bitmaps or vectors.
    * @param[in] horizontal True for horizontal layouts (set to false for vertical layouting).
    * @param[in] desiredFixedSize The metrics for fixed-size fonts will be scaled to this desired size (in pixels).
    * @return True if all of the requested metrics were found.
    */
-  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal = true, int desiredFixedSize = 0 );
+  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal = true, int desiredFixedSize = 0 );
 
   /**
-   * @brief Render a bitmap representation of a glyph.
+   * @brief Create a bitmap representation of a glyph.
    *
    * @param[in] fontId The ID of the font.
    * @param[in] glyphIndex The index of a glyph within the specified font.
@@ -306,6 +307,24 @@ public:
   BufferImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex );
 
   /**
+   * @brief Create a vector representation of a glyph.
+   *
+   * @note This feature requires highp shader support and is not available on all platforms
+   * @param[in] fontId The ID of the font.
+   * @param[in] glyphIndex The index of a glyph within the specified font.
+   * @param[out] blob A blob of data; this is owned by FontClient and should be copied by the caller of CreateVectorData().
+   * @param[out] blobLength The length of the blob data, or zero if the blob creation failed.
+   * @param[out] nominalWidth The width of the blob.
+   * @param[out] nominalHeight The height of the blob.
+   */
+  void CreateVectorBlob( FontId fontId,
+                         GlyphIndex glyphIndex,
+                         VectorBlob*& blob,
+                         unsigned int& blobLength,
+                         unsigned int& nominalWidth,
+                         unsigned int& nominalHeight );
+
+  /**
    * @brief Retrieves the ellipsis glyph for a requested point size.
    *
    * @param[in] pointSize The requested point size.
index 1bbc1e4..a6be687 100644 (file)
@@ -58,6 +58,20 @@ enum
   WORD_NO_BREAK = 1u, ///< Text can't be broken into a new word.
 };
 
+enum GlyphType
+{
+  BITMAP_GLYPH, ///< Glyph stored as pixels.
+  VECTOR_GLYPH  ///< Glyph stored as vectors (scalable). This feature requires highp shader support and is not available on all platforms.
+};
+
+struct VectorBlob
+{
+  unsigned char r;
+  unsigned char g;
+  unsigned char b;
+  unsigned char a;
+};
+
 } // namespace TextAbstraction
 
 } // namespace Dali
diff --git a/text/dali/internal/glyphy/file.list b/text/dali/internal/glyphy/file.list
new file mode 100644 (file)
index 0000000..6622a58
--- /dev/null
@@ -0,0 +1,9 @@
+# Add local source files here:
+
+static_libraries_glyphy_src_files = \
+  $(static_libraries_glyphy_src_dir)/glyphy-arcs.cc \
+  $(static_libraries_glyphy_src_dir)/glyphy-blob-impl.cc \
+  $(static_libraries_glyphy_src_dir)/glyphy-extents.cc \
+  $(static_libraries_glyphy_src_dir)/glyphy-outline.cc \
+  $(static_libraries_glyphy_src_dir)/glyphy-sdf.cc \
+  $(static_libraries_glyphy_src_dir)/vector-font-cache.cpp
diff --git a/text/dali/internal/glyphy/glyphy-arc-bezier.hh b/text/dali/internal/glyphy/glyphy-arc-bezier.hh
new file mode 100644 (file)
index 0000000..a3c71aa
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2012,2013 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef GLYPHY_ARC_BEZIER_HH
+#define GLYPHY_ARC_BEZIER_HH
+
+#include "glyphy-common.hh"
+#include "glyphy-geometry.hh"
+
+namespace GLyphy {
+namespace ArcBezier {
+
+using namespace Geometry;
+
+
+class MaxDeviationApproximatorExact
+{
+  public:
+  /* Returns 3 max(abs(d₀ t (1-t)² + d₁ t² (1-t)) for 0≤t≤1. */
+  static double approximate_deviation (double d0, double d1)
+  {
+    double candidates[4] = {0,1};
+    unsigned int num_candidates = 2;
+    if (d0 == d1)
+      candidates[num_candidates++] = .5;
+    else {
+      double delta = d0*d0 - d0*d1 + d1*d1;
+      double t2 = 1. / (3 * (d0 - d1));
+      double t0 = (2 * d0 - d1) * t2;
+      if (delta == 0)
+        candidates[num_candidates++] = t0;
+      else if (delta > 0) {
+        /* This code can be optimized to avoid the sqrt if the solution
+         * is not feasible (ie. lies outside (0,1)).  I have implemented
+         * that in cairo-spline.c:_cairo_spline_bound().  Can be reused
+         * here.
+         */
+        double t1 = sqrt (delta) * t2;
+        candidates[num_candidates++] = t0 - t1;
+        candidates[num_candidates++] = t0 + t1;
+      }
+    }
+
+    double e = 0;
+    for (unsigned int i = 0; i < num_candidates; i++) {
+      double t = candidates[i];
+      double ee;
+      if (t < 0. || t > 1.)
+        continue;
+      ee = fabs (3 * t * (1-t) * (d0 * (1 - t) + d1 * t));
+      e = std::max (e, ee);
+    }
+
+    return e;
+  }
+};
+
+
+
+template <class MaxDeviationApproximator>
+class ArcBezierErrorApproximatorBehdad
+{
+  public:
+  static double approximate_bezier_arc_error (const Bezier &b0, const Arc &a)
+  {
+    assert (b0.p0 == a.p0);
+    assert (b0.p3 == a.p1);
+
+    double ea;
+    Bezier b1 = a.approximate_bezier (&ea);
+
+    assert (b0.p0 == b1.p0);
+    assert (b0.p3 == b1.p3);
+
+    Vector v0 = b1.p1 - b0.p1;
+    Vector v1 = b1.p2 - b0.p2;
+
+    Vector b = (b0.p3 - b0.p0).normalized ();
+    v0 = v0.rebase (b);
+    v1 = v1.rebase (b);
+
+    Vector v (MaxDeviationApproximator::approximate_deviation (v0.dx, v1.dx),
+              MaxDeviationApproximator::approximate_deviation (v0.dy, v1.dy));
+
+    /* Edge cases: If d*d is too close too large default to a weak bound. */
+    if (a.d * a.d > 1. - 1e-4)
+      return ea + v.len ();
+
+    /* If the wedge doesn't contain control points, default to weak bound. */
+    if (!a.wedge_contains_point (b0.p1) || !a.wedge_contains_point (b0.p2))
+      return ea + v.len ();
+
+    /* If straight line, return the max ortho deviation. */
+    if (fabs (a.d) < 1e-6)
+      return ea + v.dy;
+
+    /* We made sure that fabs(a.d) < 1 */
+    double tan_half_alpha = fabs (tan2atan (a.d));
+
+    double tan_v = v.dx / v.dy;
+
+    double eb;
+    if (fabs (tan_v) <= tan_half_alpha)
+      return ea + v.len ();
+
+    double c2 = (a.p1 - a.p0).len () * .5;
+    double r = a.radius ();
+
+    eb = Vector (c2 + v.dx, c2 / tan_half_alpha + v.dy).len () - r;
+    assert (eb >= 0);
+
+    return ea + eb;
+  }
+};
+
+
+
+template <class ArcBezierErrorApproximator>
+class ArcBezierApproximatorMidpointSimple
+{
+  public:
+  static const Arc approximate_bezier_with_arc (const Bezier &b, double *error)
+  {
+    Arc a (b.p0, b.p3, b.midpoint (), false);
+
+    *error = ArcBezierErrorApproximator::approximate_bezier_arc_error (b, a);
+
+    return a;
+  }
+};
+
+template <class ArcBezierErrorApproximator>
+class ArcBezierApproximatorMidpointTwoPart
+{
+  public:
+  static const Arc approximate_bezier_with_arc (const Bezier &b, double *error, double mid_t = .5)
+  {
+    Pair<Bezier > pair = b.split (mid_t);
+    Point m = pair.second.p0;
+
+    Arc a0 (b.p0, m, b.p3, true);
+    Arc a1 (m, b.p3, b.p0, true);
+
+    double e0 = ArcBezierErrorApproximator::approximate_bezier_arc_error (pair.first, a0);
+    double e1 = ArcBezierErrorApproximator::approximate_bezier_arc_error (pair.second, a1);
+    *error = std::max (e0, e1);
+
+    return Arc (b.p0, b.p3, m, false);
+  }
+};
+
+template <class ArcBezierErrorApproximator>
+class ArcBezierApproximatorQuantized
+{
+  public:
+  ArcBezierApproximatorQuantized (double _max_d = GLYPHY_INFINITY, unsigned int _d_bits = 0) :
+    max_d (_max_d), d_bits (_d_bits) {};
+
+  protected:
+  double max_d;
+  unsigned int d_bits;
+
+  public:
+  const Arc approximate_bezier_with_arc (const Bezier &b, double *error) const
+  {
+    double mid_t = .5;
+    Arc a (b.p0, b.p3, b.point (mid_t), false);
+    Arc orig_a = a;
+
+    if (isfinite (max_d)) {
+      assert (max_d >= 0);
+      if (fabs (a.d) > max_d)
+        a.d = a.d < 0 ? -max_d : max_d;
+    }
+    if (d_bits && max_d != 0) {
+      assert (isfinite (max_d));
+      assert (fabs (a.d) <= max_d);
+      int mult = (1 << (d_bits - 1)) - 1;
+      int id = round (a.d / max_d * mult);
+      assert (-mult <= id && id <= mult);
+      a.d = id * max_d / mult;
+      assert (fabs (a.d) <= max_d);
+    }
+
+    /* Error introduced by arc quantization */
+    double ed = fabs (a.d - orig_a.d) * (a.p1 - a.p0).len () * .5;
+
+    ArcBezierApproximatorMidpointTwoPart<ArcBezierErrorApproximator>
+            ::approximate_bezier_with_arc (b, error, mid_t);
+
+    if (ed) {
+      *error += ed;
+
+      /* Try a simple one-arc approx which works with the quantized arc.
+       * May produce smaller error bound. */
+      double e = ArcBezierErrorApproximator::approximate_bezier_arc_error (b, a);
+      if (e < *error)
+        *error = e;
+    }
+
+    return a;
+  }
+};
+
+typedef MaxDeviationApproximatorExact MaxDeviationApproximatorDefault;
+typedef ArcBezierErrorApproximatorBehdad<MaxDeviationApproximatorDefault> ArcBezierErrorApproximatorDefault;
+typedef ArcBezierApproximatorMidpointTwoPart<ArcBezierErrorApproximatorDefault> ArcBezierApproximatorDefault;
+typedef ArcBezierApproximatorQuantized<ArcBezierErrorApproximatorDefault> ArcBezierApproximatorQuantizedDefault;
+
+} /* namespace ArcBezier */
+} /* namespace GLyphy */
+
+#endif /* GLYPHY_ARC_BEZIER_HH */
diff --git a/text/dali/internal/glyphy/glyphy-arcs-bezier.hh b/text/dali/internal/glyphy/glyphy-arcs-bezier.hh
new file mode 100644 (file)
index 0000000..28ebc6b
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef GLYPHY_ARCS_BEZIER_HH
+#define GLYPHY_ARCS_BEZIER_HH
+
+#include "glyphy-common.hh"
+#include "glyphy-geometry.hh"
+#include "glyphy-arc-bezier.hh"
+
+namespace GLyphy {
+namespace ArcsBezier {
+
+using namespace Geometry;
+using namespace ArcBezier;
+
+template <class ArcBezierApproximator>
+class ArcsBezierApproximatorSpringSystem
+{
+  static inline void calc_arcs (const Bezier &b,
+                                const std::vector<double> &t,
+                                const ArcBezierApproximator &appx,
+                                std::vector<double> &e,
+                                std::vector<Arc > &arcs,
+                                double &max_e, double &min_e)
+  {
+    unsigned int n = t.size () - 1;
+    e.resize (n);
+    arcs.clear ();
+    max_e = 0;
+    min_e = GLYPHY_INFINITY;
+    for (unsigned int i = 0; i < n; i++)
+    {
+      Bezier segment = b.segment (t[i], t[i + 1]);
+      arcs.push_back (appx.approximate_bezier_with_arc (segment, &e[i]));
+
+      max_e = std::max (max_e, e[i]);
+      min_e = std::min (min_e, e[i]);
+    }
+  }
+
+  static inline void jiggle (const Bezier &b,
+                             const ArcBezierApproximator &appx,
+                             std::vector<double> &t,
+                             std::vector<double> &e,
+                             std::vector<Arc > &arcs,
+                             double &max_e, double &min_e,
+                             double tolerance,
+                             unsigned int &n_jiggle)
+  {
+    unsigned int n = t.size () - 1;
+    unsigned int max_jiggle = log2 (n) + 1;
+    unsigned int s;
+    for (s = 0; s < max_jiggle; s++)
+    {
+      double total = 0;
+      for (unsigned int i = 0; i < n; i++) {
+        double l = t[i + 1] - t[i];
+        double k_inv = l * pow (e[i], -.3);
+        total += k_inv;
+        e[i] = k_inv;
+      }
+      for (unsigned int i = 0; i < n; i++) {
+        double k_inv = e[i];
+        double l = k_inv / total;
+        t[i + 1] = t[i] + l;
+      }
+      t[n] = 1.0; // Do this to get real 1.0, not .9999999999999998!
+
+      calc_arcs (b, t, appx, e, arcs, max_e, min_e);
+
+      n_jiggle++;
+      if (max_e < tolerance || (2 * min_e - max_e > tolerance))
+        break;
+    }
+  }
+
+  public:
+  static void approximate_bezier_with_arcs (const Bezier &b,
+                                            double tolerance,
+                                            const ArcBezierApproximator &appx,
+                                            std::vector<Arc> &arcs,
+                                            double *perror,
+                                            unsigned int max_segments = 100)
+  {
+    std::vector<double> t;
+    std::vector<double> e;
+    double max_e, min_e;
+    unsigned int n_jiggle = 0;
+
+    /* Technically speaking we can bsearch for n. */
+    for (unsigned int n = 1; n <= max_segments; n++)
+    {
+      t.resize (n + 1);
+      for (unsigned int i = 0; i < n; i++)
+        t[i] = double (i) / n;
+      t[n] = 1.0; // Do this out of the loop to get real 1.0, not .9999999999999998!
+
+      calc_arcs (b, t, appx, e, arcs, max_e, min_e);
+
+      for (unsigned int i = 0; i < n; i++)
+        if (e[i] <= tolerance) {
+          jiggle (b, appx, t, e, arcs, max_e, min_e, tolerance, n_jiggle);
+          break;
+        }
+
+      if (max_e <= tolerance)
+        break;
+    }
+    if (perror)
+      *perror = max_e;
+  }
+};
+
+} /* namespace ArcsBezier */
+} /* namespace GLyphy */
+
+#endif /* GLYPHY_ARCS_BEZIER_HH */
diff --git a/text/dali/internal/glyphy/glyphy-arcs.cc b/text/dali/internal/glyphy/glyphy-arcs.cc
new file mode 100644 (file)
index 0000000..be9e46d
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju, Wojciech Baranowski
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glyphy-common.hh"
+#include "glyphy-geometry.hh"
+#include "glyphy-arcs-bezier.hh"
+
+using namespace GLyphy::Geometry;
+using namespace GLyphy::ArcsBezier;
+
+
+
+/*
+ * Approximate outlines with multiple arcs
+ */
+
+
+struct glyphy_arc_accumulator_t {
+  unsigned int refcount;
+
+  double tolerance;
+  unsigned int d_bits;
+  glyphy_arc_endpoint_accumulator_callback_t  callback;
+  void                                       *user_data;
+
+  glyphy_point_t start_point;
+  glyphy_point_t current_point;
+  bool           need_moveto;
+  unsigned int   num_endpoints;
+  double max_error;
+  glyphy_bool_t success;
+};
+
+
+glyphy_arc_accumulator_t *
+glyphy_arc_accumulator_create (void)
+{
+  glyphy_arc_accumulator_t *acc = (glyphy_arc_accumulator_t *) calloc (1, sizeof (glyphy_arc_accumulator_t));
+  acc->refcount = 1;
+
+  acc->tolerance = 5e-4;
+  acc->d_bits = 8;
+  acc->callback = NULL;
+  acc->user_data = NULL;
+
+  glyphy_arc_accumulator_reset (acc);
+
+  return acc;
+}
+
+void
+glyphy_arc_accumulator_reset (glyphy_arc_accumulator_t *acc)
+{
+  acc->start_point = acc->current_point = Point (0, 0);
+  acc->need_moveto = true;
+  acc->num_endpoints = 0;
+  acc->max_error = 0;
+  acc->success = true;
+}
+
+void
+glyphy_arc_accumulator_destroy (glyphy_arc_accumulator_t *acc)
+{
+  if (!acc || --acc->refcount)
+    return;
+
+  free (acc);
+}
+
+/* Configure acc */
+
+void
+glyphy_arc_accumulator_set_tolerance (glyphy_arc_accumulator_t *acc,
+                                      double                    tolerance)
+{
+  acc->tolerance = tolerance;
+}
+
+double
+glyphy_arc_accumulator_get_tolerance (glyphy_arc_accumulator_t *acc)
+{
+  return acc->tolerance;
+}
+
+void
+glyphy_arc_accumulator_set_callback (glyphy_arc_accumulator_t *acc,
+                                     glyphy_arc_endpoint_accumulator_callback_t callback,
+                                     void                     *user_data)
+{
+  acc->callback = callback;
+  acc->user_data = user_data;
+}
+
+void
+glyphy_arc_accumulator_get_callback (glyphy_arc_accumulator_t  *acc,
+                                     glyphy_arc_endpoint_accumulator_callback_t *callback,
+                                     void                     **user_data)
+{
+  *callback = acc->callback;
+  *user_data = acc->user_data;
+}
+
+/* Accumulation results */
+
+double
+glyphy_arc_accumulator_get_error (glyphy_arc_accumulator_t *acc)
+{
+  return acc->max_error;
+}
+
+glyphy_bool_t
+glyphy_arc_accumulator_successful (glyphy_arc_accumulator_t *acc)
+{
+  return acc->success;
+}
+
+
+/* Accumulate */
+
+static void
+emit (glyphy_arc_accumulator_t *acc, const Point &p, double d)
+{
+  glyphy_arc_endpoint_t endpoint = {p, d};
+  acc->success = acc->success && acc->callback (&endpoint, acc->user_data);
+  if (acc->success) {
+    acc->num_endpoints++;
+    acc->current_point = p;
+  }
+}
+
+static void
+accumulate (glyphy_arc_accumulator_t *acc, const Point &p, double d)
+{
+  if (Point (acc->current_point) == p)
+    return;
+  if (d == GLYPHY_INFINITY) {
+    /* Emit moveto lazily, for cleaner outlines */
+    acc->need_moveto = true;
+    acc->current_point = p;
+    return;
+  }
+  if (acc->need_moveto) {
+    emit (acc, acc->current_point, GLYPHY_INFINITY);
+    if (acc->success) {
+      acc->start_point = acc->current_point;
+      acc->need_moveto = false;
+    }
+  }
+  emit (acc, p, d);
+}
+
+static void
+move_to (glyphy_arc_accumulator_t *acc, const Point &p)
+{
+  if (!acc->num_endpoints || p != acc->current_point)
+    accumulate (acc, p, GLYPHY_INFINITY);
+}
+
+static void
+arc_to (glyphy_arc_accumulator_t *acc, const Point &p1, double d)
+{
+  accumulate (acc, p1, d);
+}
+
+static void
+bezier (glyphy_arc_accumulator_t *acc, const Bezier &b)
+{
+  double e;
+
+  std::vector<Arc> arcs;
+  typedef ArcBezierApproximatorQuantizedDefault _ArcBezierApproximator;
+  _ArcBezierApproximator appx (GLYPHY_MAX_D, acc->d_bits);
+  ArcsBezierApproximatorSpringSystem<_ArcBezierApproximator>
+    ::approximate_bezier_with_arcs (b, acc->tolerance, appx, arcs, &e);
+
+  acc->max_error = std::max (acc->max_error, e);
+
+  move_to (acc, b.p0);
+  for (unsigned int i = 0; i < arcs.size (); i++)
+    arc_to (acc, arcs[i].p1, arcs[i].d);
+}
+
+static void
+close_path (glyphy_arc_accumulator_t *acc)
+{
+  if (!acc->need_moveto && Point (acc->current_point) != Point (acc->start_point))
+    arc_to (acc, acc->start_point, 0);
+}
+
+void
+glyphy_arc_accumulator_move_to (glyphy_arc_accumulator_t *acc,
+                                const glyphy_point_t *p0)
+{
+  move_to (acc, *p0);
+}
+
+void
+glyphy_arc_accumulator_line_to (glyphy_arc_accumulator_t *acc,
+                                const glyphy_point_t *p1)
+{
+  arc_to (acc, *p1, 0);
+}
+
+void
+glyphy_arc_accumulator_conic_to (glyphy_arc_accumulator_t *acc,
+                                 const glyphy_point_t *p1,
+                                 const glyphy_point_t *p2)
+{
+  bezier (acc, Bezier (acc->current_point,
+                       Point (acc->current_point).lerp (2/3., *p1),
+                       Point (*p2).lerp (2/3., *p1),
+                       *p2));
+}
+
+void
+glyphy_arc_accumulator_cubic_to (glyphy_arc_accumulator_t *acc,
+                                 const glyphy_point_t *p1,
+                                 const glyphy_point_t *p2,
+                                 const glyphy_point_t *p3)
+{
+  bezier (acc, Bezier (acc->current_point, *p1, *p2, *p3));
+}
+
+void
+glyphy_arc_accumulator_arc_to (glyphy_arc_accumulator_t *acc,
+                               const glyphy_point_t *p1,
+                               double         d)
+{
+  arc_to (acc, *p1, d);
+}
+
+void
+glyphy_arc_accumulator_close_path (glyphy_arc_accumulator_t *acc)
+{
+  close_path (acc);
+}
+
+
+
+/*
+ * Outline extents from arc list
+ */
+
+
+void
+glyphy_arc_list_extents (const glyphy_arc_endpoint_t *endpoints,
+                         unsigned int                 num_endpoints,
+                         glyphy_extents_t            *extents)
+{
+  Point p0 (0, 0);
+  glyphy_extents_clear (extents);
+  for (unsigned int i = 0; i < num_endpoints; i++) {
+    const glyphy_arc_endpoint_t &endpoint = endpoints[i];
+    if (endpoint.d == GLYPHY_INFINITY) {
+      p0 = endpoint.p;
+      continue;
+    }
+    Arc arc (p0, endpoint.p, endpoint.d);
+    p0 = endpoint.p;
+
+    glyphy_extents_t arc_extents;
+    arc.extents (arc_extents);
+    glyphy_extents_extend (extents, &arc_extents);
+  }
+}
diff --git a/text/dali/internal/glyphy/glyphy-blob-impl.cc b/text/dali/internal/glyphy/glyphy-blob-impl.cc
new file mode 100644 (file)
index 0000000..84caf28
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju, Wojciech Baranowski
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glyphy-common.hh"
+#include "glyphy-geometry.hh"
+
+#define GRID_SIZE 24
+
+using namespace GLyphy::Geometry;
+
+
+#define UPPER_BITS(v,bits,total_bits) ((v) >> ((total_bits) - (bits)))
+#define LOWER_BITS(v,bits,total_bits) ((v) & ((1 << (bits)) - 1))
+
+#define MAX_X 4095
+#define MAX_Y 4095
+
+static inline glyphy_rgba_t
+arc_endpoint_encode (unsigned int ix, unsigned int iy, double d)
+{
+  glyphy_rgba_t v;
+
+  /* 12 bits for each of x and y, 8 bits for d */
+  assert (ix <= MAX_X);
+  assert (iy <= MAX_Y);
+  unsigned int id;
+  if (isinf (d))
+    id = 0;
+  else {
+    assert (fabs (d) <= GLYPHY_MAX_D);
+    id = 128 + lround (d * 127 / GLYPHY_MAX_D);
+  }
+  assert (id < 256);
+
+  v.r = id;
+  v.g = LOWER_BITS (ix, 8, 12);
+  v.b = LOWER_BITS (iy, 8, 12);
+  v.a = ((ix >> 8) << 4) | (iy >> 8);
+  return v;
+}
+
+static inline glyphy_rgba_t
+arc_list_encode (unsigned int offset, unsigned int num_points, int side)
+{
+  glyphy_rgba_t v;
+  v.r = 0; // unused for arc-list encoding
+  v.g = UPPER_BITS (offset, 8, 16);
+  v.b = LOWER_BITS (offset, 8, 16);
+  v.a = LOWER_BITS (num_points, 8, 8);
+  if (side < 0 && !num_points)
+    v.a = 255;
+  return v;
+}
+
+static inline glyphy_rgba_t
+line_encode (const Line &line)
+{
+  Line l = line.normalized ();
+  double angle = l.n.angle ();
+  double distance = l.c;
+
+  int ia = lround (-angle / M_PI * 0x7FFF);
+  unsigned int ua = ia + 0x8000;
+  assert (0 == (ua & ~0xFFFF));
+
+  int id = lround (distance * 0x1FFF);
+  unsigned int ud = id + 0x4000;
+  assert (0 == (ud & ~0x7FFF));
+
+  /* Marker for line-encoded */
+  ud |= 0x8000;
+
+  glyphy_rgba_t v;
+  v.r = ud >> 8;
+  v.g = ud & 0xFF;
+  v.b = ua >> 8;
+  v.a = ua & 0xFF;
+  return v;
+}
+
+
+/* Given a cell, fills the vector closest_arcs with arcs that may be closest to some point in the cell.
+ * Uses idea that all close arcs to cell must be ~close to center of cell.
+ */
+static void
+closest_arcs_to_cell (Point c0, Point c1, /* corners */
+                      double faraway,
+                      const glyphy_arc_endpoint_t *endpoints,
+                      unsigned int num_endpoints,
+                      std::vector<glyphy_arc_endpoint_t> &near_endpoints,
+                      int *side)
+{
+  // Find distance between cell center
+  Point c = c0.midpoint (c1);
+  double min_dist = glyphy_sdf_from_arc_list (endpoints, num_endpoints, &c, NULL);
+
+  *side = min_dist >= 0 ? +1 : -1;
+  min_dist = fabs (min_dist);
+  std::vector<Arc> near_arcs;
+
+  // If d is the distance from the center of the square to the nearest arc, then
+  // all nearest arcs to the square must be at most almost [d + half_diagonal] from the center.
+  double half_diagonal = (c - c0).len ();
+  double radius_squared = pow (min_dist + half_diagonal, 2);
+  if (min_dist - half_diagonal <= faraway) {
+    Point p0 (0, 0);
+    for (unsigned int i = 0; i < num_endpoints; i++) {
+      const glyphy_arc_endpoint_t &endpoint = endpoints[i];
+      if (endpoint.d == GLYPHY_INFINITY) {
+        p0 = endpoint.p;
+        continue;
+      }
+      Arc arc (p0, endpoint.p, endpoint.d);
+      p0 = endpoint.p;
+
+      if (arc.squared_distance_to_point (c) <= radius_squared)
+        near_arcs.push_back (arc);
+    }
+  }
+
+  Point p1 = Point (0, 0);
+  for (unsigned i = 0; i < near_arcs.size (); i++)
+  {
+    Arc arc = near_arcs[i];
+
+    if (i == 0 || p1 != arc.p0) {
+      glyphy_arc_endpoint_t endpoint = {arc.p0, GLYPHY_INFINITY};
+      near_endpoints.push_back (endpoint);
+      p1 = arc.p0;
+    }
+
+    glyphy_arc_endpoint_t endpoint = {arc.p1, arc.d};
+    near_endpoints.push_back (endpoint);
+    p1 = arc.p1;
+  }
+}
+
+
+glyphy_bool_t
+glyphy_arc_list_encode_blob (const glyphy_arc_endpoint_t *endpoints,
+                             unsigned int                 num_endpoints,
+                             glyphy_rgba_t               *blob,
+                             unsigned int                 blob_size,
+                             double                       faraway,
+                             double                       avg_fetch_desired,
+                             double                      *avg_fetch_achieved,
+                             unsigned int                *output_len,
+                             unsigned int                *nominal_width,  /* 8bit */
+                             unsigned int                *nominal_height, /* 8bit */
+                             glyphy_extents_t            *pextents)
+{
+  glyphy_extents_t extents;
+  glyphy_extents_clear (&extents);
+
+  glyphy_arc_list_extents (endpoints, num_endpoints, &extents);
+
+  if (glyphy_extents_is_empty (&extents)) {
+    *pextents = extents;
+    if (!blob_size)
+      return false;
+    *blob = arc_list_encode (0, 0, +1);
+    *avg_fetch_achieved = 1;
+    *output_len = 1;
+    *nominal_width = *nominal_height = 1;
+    return true;
+  }
+
+  /* Add antialiasing padding */
+  extents.min_x -= faraway;
+  extents.min_y -= faraway;
+  extents.max_x += faraway;
+  extents.max_y += faraway;
+
+  double glyph_width = extents.max_x - extents.min_x;
+  double glyph_height = extents.max_y - extents.min_y;
+  double unit = std::max (glyph_width, glyph_height);
+
+  unsigned int grid_w = GRID_SIZE;
+  unsigned int grid_h = GRID_SIZE;
+
+  if (glyph_width > glyph_height) {
+    while ((grid_h - 1) * unit / grid_w > glyph_height)
+      grid_h--;
+    glyph_height = grid_h * unit / grid_w;
+    extents.max_y = extents.min_y + glyph_height;
+  } else {
+    while ((grid_w - 1) * unit / grid_h > glyph_width)
+      grid_w--;
+    glyph_width = grid_w * unit / grid_h;
+    extents.max_x = extents.min_x + glyph_width;
+  }
+
+  double cell_unit = unit / std::max (grid_w, grid_h);
+
+  std::vector<glyphy_rgba_t> tex_data;
+  std::vector<glyphy_arc_endpoint_t> near_endpoints;
+
+  unsigned int header_length = grid_w * grid_h;
+  unsigned int offset = header_length;
+  tex_data.resize (header_length);
+  Point origin = Point (extents.min_x, extents.min_y);
+  unsigned int total_arcs = 0;
+
+  for (unsigned int row = 0; row < grid_h; row++)
+    for (unsigned int col = 0; col < grid_w; col++)
+    {
+      Point cp0 = origin + Vector ((col + 0) * cell_unit, (row + 0) * cell_unit);
+      Point cp1 = origin + Vector ((col + 1) * cell_unit, (row + 1) * cell_unit);
+      near_endpoints.clear ();
+
+      int side;
+      closest_arcs_to_cell (cp0, cp1,
+                            faraway,
+                            endpoints, num_endpoints,
+                            near_endpoints,
+                            &side);
+
+#define QUANTIZE_X(X) (lround (MAX_X * ((X - extents.min_x) / glyph_width )))
+#define QUANTIZE_Y(Y) (lround (MAX_Y * ((Y - extents.min_y) / glyph_height)))
+#define DEQUANTIZE_X(X) (double (X) / MAX_X * glyph_width  + extents.min_x)
+#define DEQUANTIZE_Y(Y) (double (Y) / MAX_Y * glyph_height + extents.min_y)
+#define SNAP(P) (Point (DEQUANTIZE_X (QUANTIZE_X ((P).x)), DEQUANTIZE_Y (QUANTIZE_Y ((P).y))))
+
+      if (near_endpoints.size () == 2 && near_endpoints[1].d == 0) {
+              Point c (extents.min_x + glyph_width * .5, extents.min_y + glyph_height * .5);
+              Line line (SNAP (near_endpoints[0].p), SNAP (near_endpoints[1].p));
+              line.c -= line.n * Vector (c);
+              line.c /= unit;
+              tex_data[row * grid_w + col] = line_encode (line);
+              continue;
+      }
+
+      /* If the arclist is two arcs that can be combined in encoding if reordered,
+       * do that. */
+      if (near_endpoints.size () == 4 &&
+          isinf (near_endpoints[2].d) &&
+          near_endpoints[0].p.x == near_endpoints[3].p.x &&
+          near_endpoints[0].p.y == near_endpoints[3].p.y)
+      {
+              glyphy_arc_endpoint_t e0, e1, e2;
+              e0 = near_endpoints[2];
+              e1 = near_endpoints[3];
+              e2 = near_endpoints[1];
+              near_endpoints.resize (0);
+              near_endpoints.push_back (e0);
+              near_endpoints.push_back (e1);
+              near_endpoints.push_back (e2);
+      }
+
+      for (unsigned i = 0; i < near_endpoints.size (); i++) {
+        glyphy_arc_endpoint_t &endpoint = near_endpoints[i];
+        tex_data.push_back (arc_endpoint_encode (QUANTIZE_X(endpoint.p.x), QUANTIZE_Y(endpoint.p.y), endpoint.d));
+      }
+
+      unsigned int current_endpoints = tex_data.size () - offset;
+
+      if (current_endpoints)
+      {
+        /* See if we can fulfill this cell by using already-encoded arcs */
+        const glyphy_rgba_t *needle = &tex_data[offset];
+        unsigned int needle_len = current_endpoints;
+        const glyphy_rgba_t *haystack = &tex_data[header_length];
+        unsigned int haystack_len = offset - header_length;
+
+        bool found = false;
+        while (haystack_len >= needle_len) {
+          /* Trick: we don't care about first endpoint's d value, so skip one
+           * byte in comparison.  This works because arc_encode() packs the
+           * d value in the first byte. */
+          if (0 == memcmp (1 + (const char *) needle,
+                           1 + (const char *) haystack,
+                           needle_len * sizeof (*needle) - 1)) {
+            found = true;
+            break;
+          }
+          haystack++;
+          haystack_len--;
+        }
+        if (found) {
+          unsigned int new_offset = haystack - &tex_data[0];
+          tex_data.resize (offset);
+          haystack = needle = NULL; /* Invalidated by the resize. */
+          offset = new_offset;
+        }
+      }
+      else
+        offset = 0;
+
+      tex_data[row * grid_w + col] = arc_list_encode (offset, current_endpoints, side);
+      offset = tex_data.size ();
+
+      total_arcs += current_endpoints;
+    }
+
+  if (avg_fetch_achieved)
+    *avg_fetch_achieved = 1 + double (total_arcs) / (grid_w * grid_h);
+
+  *pextents = extents;
+
+  if (tex_data.size () > blob_size)
+    return false;
+
+  memcpy (blob, &tex_data[0], tex_data.size () * sizeof(tex_data[0]));
+  *output_len = tex_data.size ();
+  *nominal_width = grid_w;
+  *nominal_height = grid_h;
+
+  return true;
+}
diff --git a/text/dali/internal/glyphy/glyphy-common.hh b/text/dali/internal/glyphy/glyphy-common.hh
new file mode 100644 (file)
index 0000000..8d4d02c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef GLYPHY_COMMON_HH
+#define GLYPHY_COMMON_HH
+
+#include "glyphy.h"
+
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <vector>
+#include <algorithm>
+
+#ifndef GLYPHY_EPSILON
+#  define GLYPHY_EPSILON  1e-5
+#endif
+#ifndef GLYPHY_INFINITY
+#  define GLYPHY_INFINITY INFINITY
+#endif
+
+
+static inline bool
+iszero (double v)
+{
+  return fabs (v) < 2 * GLYPHY_EPSILON;
+}
+
+
+#define GLYPHY_MAX_D .5
+
+#undef  ARRAY_LENGTH
+#define ARRAY_LENGTH(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
+
+#define _ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
+#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond))
+#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))
+
+#ifdef __ANDROID__
+#define log2(x) (log(x) / log(2.0))
+#endif
+
+#endif /* GLYPHY_COMMON_HH */
diff --git a/text/dali/internal/glyphy/glyphy-extents.cc b/text/dali/internal/glyphy/glyphy-extents.cc
new file mode 100644 (file)
index 0000000..bccc861
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glyphy-common.hh"
+
+
+void
+glyphy_extents_clear (glyphy_extents_t *extents)
+{
+  extents->min_x =  GLYPHY_INFINITY;
+  extents->min_y =  GLYPHY_INFINITY;
+  extents->max_x = -GLYPHY_INFINITY;
+  extents->max_y = -GLYPHY_INFINITY;
+}
+
+glyphy_bool_t
+glyphy_extents_is_empty (const glyphy_extents_t *extents)
+{
+  return isinf (extents->min_x);
+}
+
+void
+glyphy_extents_add (glyphy_extents_t     *extents,
+                    const glyphy_point_t *p)
+{
+  if (glyphy_extents_is_empty (extents)) {
+    extents->min_x = extents->max_x = p->x;
+    extents->min_y = extents->max_y = p->y;
+    return;
+  }
+  extents->min_x = std::min (extents->min_x, p->x);
+  extents->min_y = std::min (extents->min_y, p->y);
+  extents->max_x = std::max (extents->max_x, p->x);
+  extents->max_y = std::max (extents->max_y, p->y);
+}
+
+void
+glyphy_extents_extend (glyphy_extents_t       *extents,
+                       const glyphy_extents_t *other)
+{
+  if (glyphy_extents_is_empty (other))
+    return;
+  if (glyphy_extents_is_empty (extents)) {
+    *extents = *other;
+    return;
+  }
+  extents->min_x = std::min (extents->min_x, other->min_x);
+  extents->min_y = std::min (extents->min_y, other->min_y);
+  extents->max_x = std::max (extents->max_x, other->max_x);
+  extents->max_y = std::max (extents->max_y, other->max_y);
+}
+
+glyphy_bool_t
+glyphy_extents_includes (const glyphy_extents_t *extents,
+                         const glyphy_point_t   *p)
+{
+  return extents->min_x <= p->x && p->x <= extents->max_x &&
+         extents->min_y <= p->y && p->y <= extents->max_y;
+}
+
+void
+glyphy_extents_scale (glyphy_extents_t *extents,
+                      double            x_scale,
+                      double            y_scale)
+{
+  extents->min_x *= x_scale;
+  extents->max_x *= x_scale;
+  extents->min_y *= y_scale;
+  extents->max_y *= y_scale;
+}
diff --git a/text/dali/internal/glyphy/glyphy-freetype.h b/text/dali/internal/glyphy/glyphy-freetype.h
new file mode 100644 (file)
index 0000000..6105e88
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+/* Intentionally doesn't have include guards */
+
+#include "glyphy.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+
+static int
+glyphy_freetype_move_to(FT_Vector *to,
+                        glyphy_arc_accumulator_t *acc)
+{
+  glyphy_point_t p1 = {static_cast<double>(to->x), static_cast<double>(to->y)};
+  glyphy_arc_accumulator_close_path (acc);
+  glyphy_arc_accumulator_move_to (acc, &p1);
+  return glyphy_arc_accumulator_successful (acc) ? FT_Err_Ok : FT_Err_Out_Of_Memory;
+}
+
+static int
+glyphy_freetype_line_to(FT_Vector *to,
+                        glyphy_arc_accumulator_t *acc)
+{
+  glyphy_point_t p1 = {static_cast<double>(to->x), static_cast<double>(to->y)};
+  glyphy_arc_accumulator_line_to (acc, &p1);
+  return glyphy_arc_accumulator_successful (acc) ? FT_Err_Ok : FT_Err_Out_Of_Memory;
+}
+
+static int
+glyphy_freetype_conic_to(FT_Vector *control, FT_Vector *to,
+                         glyphy_arc_accumulator_t *acc)
+{
+  glyphy_point_t p1 = {static_cast<double>(control->x), static_cast<double>(control->y)};
+  glyphy_point_t p2 = {static_cast<double>(to->x), static_cast<double>(to->y)};
+  glyphy_arc_accumulator_conic_to (acc, &p1, &p2);
+  return glyphy_arc_accumulator_successful (acc) ? FT_Err_Ok : FT_Err_Out_Of_Memory;
+}
+
+static int
+glyphy_freetype_cubic_to(FT_Vector *control1, FT_Vector *control2, FT_Vector *to,
+                         glyphy_arc_accumulator_t *acc)
+{
+  glyphy_point_t p1 = {static_cast<double>(control1->x), static_cast<double>(control1->y)};
+  glyphy_point_t p2 = {static_cast<double>(control2->x), static_cast<double>(control2->y)};
+  glyphy_point_t p3 = {static_cast<double>(to->x), static_cast<double>(to->y)};
+  glyphy_arc_accumulator_cubic_to (acc, &p1, &p2, &p3);
+  return glyphy_arc_accumulator_successful (acc) ? FT_Err_Ok : FT_Err_Out_Of_Memory;
+}
+
+static FT_Error
+glyphy_freetype_outline_decompose(const FT_Outline         *outline,
+                                  glyphy_arc_accumulator_t *acc)
+{
+  const FT_Outline_Funcs outline_funcs = {
+    (FT_Outline_MoveToFunc) glyphy_freetype_move_to,
+    (FT_Outline_LineToFunc) glyphy_freetype_line_to,
+    (FT_Outline_ConicToFunc) glyphy_freetype_conic_to,
+    (FT_Outline_CubicToFunc) glyphy_freetype_cubic_to,
+    0, /* shift */
+    0, /* delta */
+  };
+
+  return FT_Outline_Decompose ((FT_Outline *) outline, &outline_funcs, acc);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/text/dali/internal/glyphy/glyphy-geometry.hh b/text/dali/internal/glyphy/glyphy-geometry.hh
new file mode 100644 (file)
index 0000000..3828676
--- /dev/null
@@ -0,0 +1,713 @@
+/*
+ * Copyright 2012,2013 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef GLYPHY_GEOMETRY_HH
+#define GLYPHY_GEOMETRY_HH
+
+#include "glyphy-common.hh"
+
+namespace GLyphy {
+namespace Geometry {
+
+template <typename Type> struct Pair;
+struct Vector;
+struct SignedVector;
+struct Point;
+struct Line;
+struct Segment;
+struct Arc;
+struct Bezier;
+
+/* returns tan (2 * atan (d)) */
+inline double tan2atan (double d) { return 2 * d / (1 - d*d); }
+
+/* returns sin (2 * atan (d)) */
+inline double sin2atan (double d) { return 2 * d / (1 + d*d); }
+
+/* returns cos (2 * atan (d)) */
+inline double cos2atan (double d) { return (1 - d*d) / (1 + d*d); }
+
+template <typename Type>
+struct Pair {
+  typedef Type ElementType;
+
+  inline Pair (const Type &first_, const Type &second_) : first (first_), second (second_) {}
+
+  Type first, second;
+};
+
+struct Point : glyphy_point_t {
+  inline Point (double x_, double y_) { x = x_; y = y_; }
+  inline explicit Point (const Vector &v);
+  inline Point (const glyphy_point_t &p) { *(glyphy_point_t *)this = p; }
+
+  inline bool operator == (const Point &p) const;
+  inline bool operator != (const Point &p) const;
+  inline Point& operator+= (const Vector &v);
+  inline Point& operator-= (const Vector &v);
+  inline const Point operator+ (const Vector &v) const;
+  inline const Point operator- (const Vector &v) const;
+  inline const Vector operator- (const Point &p) const;
+  inline const Point midpoint (const Point &p) const;
+  inline const Line bisector (const Point &p) const;
+  inline double distance_to_point (const Point &p) const; /* distance to point! */
+  inline double squared_distance_to_point (const Point &p) const; /* square of distance to point! */
+
+  inline bool is_finite (void) const;
+  inline const Point lerp (const double &a, const Point &p) const;
+};
+
+struct Vector {
+  inline Vector (double dx_, double dy_) : dx (dx_), dy (dy_) {}
+  inline explicit Vector (const Point &p) : dx (p.x), dy (p.y) {}
+
+  inline bool operator == (const Vector &v) const;
+  inline bool operator != (const Vector &v) const;
+  inline const Vector operator+ (void) const;
+  inline const Vector operator- (void) const;
+  inline Vector& operator+= (const Vector &v);
+  inline Vector& operator-= (const Vector &v);
+  inline Vector& operator*= (const double &s);
+  inline Vector& operator/= (const double &s);
+  inline const Vector operator+ (const Vector &v) const;
+  inline const Vector operator- (const Vector &v) const;
+  inline const Vector operator* (const double &s) const;
+  inline const Vector operator/ (const double &s) const;
+  inline double operator* (const Vector &v) const; /* dot product */
+  inline const Point operator+ (const Point &p) const;
+
+  inline bool is_nonzero (void) const;
+  inline double len (void) const;
+  inline double len2 (void) const;
+  inline const Vector normalized (void) const;
+  inline const Vector ortho (void) const;
+  inline const Vector normal (void) const; /* ortho().normalized() */
+  inline double angle (void) const;
+
+  inline const Vector rebase (const Vector &bx, const Vector &by) const;
+  inline const Vector rebase (const Vector &bx) const;
+
+  double dx, dy;
+};
+
+struct SignedVector : Vector {
+  inline SignedVector (const Vector &v, bool negative_) : Vector (v), negative (negative_) {}
+
+  inline bool operator == (const SignedVector &v) const;
+  inline bool operator != (const SignedVector &v) const;
+  inline const SignedVector operator- (void) const;
+
+  bool negative;
+};
+
+struct Line {
+  inline Line (double a_, double b_, double c_) : n (a_, b_), c (c_) {}
+  inline Line (Vector n_, double c_) : n (n_), c (c_) {}
+  inline Line (const Point &p0, const Point &p1) :
+               n ((p1 - p0).ortho ()), c (n * Vector (p0)) {}
+
+  inline const Point operator+ (const Line &l) const; /* line intersection! */
+  inline const SignedVector operator- (const Point &p) const; /* shortest vector from point to line */
+
+
+  inline const Line normalized (void) const;
+  inline const Vector normal (void) const;
+
+  Vector n; /* line normal */
+  double c; /* n.dx*x + n.dy*y = c */
+};
+
+struct Segment {
+  inline Segment (const Point &p0_, const Point &p1_) :
+                  p0 (p0_), p1 (p1_) {}
+
+  inline const SignedVector operator- (const Point &p) const; /* shortest vector from point to ***line*** */
+  inline double distance_to_point (const Point &p) const; /* shortest distance from point to segment */
+  inline double squared_distance_to_point (const Point &p) const; /* shortest distance squared from point to segment */
+  inline bool contains_in_span (const Point &p) const; /* is p in the stripe formed by sliding this segment? */
+  inline double max_distance_to_arc (const Arc &a) const;
+
+
+  Point p0;
+  Point p1;
+};
+
+
+
+struct Arc {
+  inline Arc (const Point &p0_, const Point &p1_, const Point &pm, bool complement) :
+              p0 (p0_), p1 (p1_),
+              d (p0_ == pm || p1_ == pm ? 0 :
+                 tan (((p1_-pm).angle () - (p0_-pm).angle ()) / 2 - (complement ? 0 : M_PI_2))) {}
+  inline Arc (const Point &p0_, const Point &p1_, const double &d_) :
+              p0 (p0_), p1 (p1_), d (d_) {}
+  inline Arc (const Point &center, double radius, const double &a0, const double &a1, bool complement) :
+              p0 (center + Vector (cos(a0),sin(a0)) * radius),
+              p1 (center + Vector (cos(a1),sin(a1)) * radius),
+              d (tan ((a1 - a0) / 4 - (complement ? 0 : M_PI_2))) {}
+  inline Arc (const glyphy_arc_t &a) : p0 (a.p0), p1 (a.p1), d (a.d) {}
+  inline operator glyphy_arc_t (void) const { glyphy_arc_t a = {p0, p1, d}; return a; }
+
+  inline bool operator == (const Arc &a) const;
+  inline bool operator != (const Arc &a) const;
+  inline const SignedVector operator- (const Point &p) const; /* shortest vector from point to arc */
+
+  inline double radius (void) const;
+  inline const Point center (void) const;
+  inline const Pair<Vector> tangents (void) const;
+
+  inline Bezier approximate_bezier (double *error) const;
+
+  inline bool wedge_contains_point (const Point &p) const;
+  inline double distance_to_point (const Point &p) const;
+  inline double squared_distance_to_point (const Point &p) const;
+  inline double extended_dist (const Point &p) const;
+
+  inline void extents (glyphy_extents_t &extents) const;
+
+  Point p0, p1;
+  double d; /* Depth */
+};
+
+struct Bezier {
+  inline Bezier (const Point &p0_, const Point &p1_,
+                 const Point &p2_, const Point &p3_) :
+                 p0 (p0_), p1 (p1_), p2 (p2_), p3 (p3_) {}
+
+  inline const Point point (const double &t) const;
+  inline const Point midpoint (void) const;
+  inline const Vector tangent (const double &t) const;
+  inline const Vector d_tangent (const double &t) const;
+  inline double curvature (const double &t) const;
+  inline const Pair<Bezier> split (const double &t) const;
+  inline const Pair<Bezier> halve (void) const;
+  inline const Bezier segment (const double &t0, const double &t1) const;
+
+  Point p0, p1, p2, p3;
+};
+
+
+/* Implementations */
+
+
+/* Point */
+
+inline Point::Point (const Vector &v) {
+  x = v.dx;
+  y = v.dy;
+}
+inline bool Point::operator == (const Point &p) const {
+  return x == p.x && y == p.y;
+}
+inline bool Point::operator != (const Point &p) const {
+  return !(*this == p);
+}
+inline Point& Point::operator+= (const Vector &v) {
+  x += v.dx;
+  y += v.dy;
+  return *this;
+}
+inline Point& Point::operator-= (const Vector &v) {
+  x -= v.dx;
+  y -= v.dy;
+  return *this;
+}
+inline const Point Point::operator+ (const Vector &v) const {
+  return Point (*this) += v;
+}
+inline const Point Point::operator- (const Vector &v) const {
+  return Point (*this) -= v;
+}
+inline const Vector Point::operator- (const Point &p) const {
+  return Vector (x - p.x, y - p.y);
+}
+
+inline const Point Point::midpoint (const Point &p) const {
+  return *this + (p - *this) / 2;
+}
+inline const Line Point::bisector (const Point &p) const {
+  Vector d = p - *this;
+  return Line (d.dx * 2, d.dy * 2, d * Vector (p) + d * Vector (*this));
+}
+
+inline double Point::distance_to_point (const Point &p) const {
+  return ((*this) - p).len ();
+}
+
+inline double Point::squared_distance_to_point (const Point &p) const {
+  return ((*this) - p).len2 ();
+}
+
+inline bool Point::is_finite (void) const {
+  return isfinite (x) && isfinite (y);
+}
+inline const Point Point::lerp (const double &a, const Point &p) const {
+  /* The following two cases are special-cased to get better floating
+   * point stability.  We require that points that are the same be
+   * bit-equal. */
+  if (a == 0)   return *this;
+  if (a == 1.0) return p;
+  return Point ((1-a) * x + a * p.x, (1-a) * y + a * p.y);
+}
+
+
+/* Vector */
+
+inline bool Vector::operator == (const Vector &v) const {
+  return dx == v.dx && dy == v.dy;
+}
+inline bool Vector::operator != (const Vector &v) const {
+  return !(*this == v);
+}
+inline const Vector Vector::operator+ (void) const {
+  return *this;
+}
+inline const Vector Vector::operator- (void) const {
+  return Vector (-dx, -dy);
+}
+inline Vector& Vector::operator+= (const Vector &v) {
+  dx += v.dx;
+  dy += v.dy;
+  return *this;
+}
+inline Vector& Vector::operator-= (const Vector &v) {
+  dx -= v.dx;
+  dy -= v.dy;
+  return *this;
+}
+inline Vector& Vector::operator*= (const double &s) {
+  dx *= s;
+  dy *= s;
+  return *this;
+}
+inline Vector& Vector::operator/= (const double &s) {
+  dx /= s;
+  dy /= s;
+  return *this;
+}
+inline const Vector Vector::operator+ (const Vector &v) const {
+  return Vector (*this) += v;
+}
+inline const Vector Vector::operator- (const Vector &v) const {
+  return Vector (*this) -= v;
+}
+inline const Vector Vector::operator* (const double &s) const {
+  return Vector (*this) *= s;
+}
+inline const Vector operator* (const double &s, const Vector &v) {
+  return v * s;
+}
+inline const Vector Vector::operator/ (const double &s) const {
+  return Vector (*this) /= s;
+}
+inline double Vector::operator* (const Vector &v) const { /* dot product */
+  return dx * v.dx + dy * v.dy;
+}
+inline const Point Vector::operator+ (const Point &p) const {
+  return p + *this;
+}
+
+inline bool Vector::is_nonzero (void) const {
+  return dx || dy;
+}
+inline double Vector::len (void) const {
+  return hypot (dx, dy);
+}
+inline double Vector::len2 (void) const {
+  return dx * dx + dy * dy;
+}
+inline const Vector Vector::normalized (void) const {
+  double d = len ();
+  return d ? *this / d : *this;
+}
+inline const Vector Vector::ortho (void) const {
+  return Vector (-dy, dx);
+}
+inline const Vector Vector::normal (void) const {
+  return ortho ().normalized ();
+}
+inline double Vector::angle (void) const {
+  return atan2 (dy, dx);
+}
+
+inline const Vector Vector::rebase (const Vector &bx,
+                                    const Vector &by) const {
+  return Vector (*this * bx, *this * by);
+}
+inline const Vector Vector::rebase (const Vector &bx) const {
+  return rebase (bx, bx.ortho ());
+}
+
+
+/* SignedVector */
+
+inline bool SignedVector::operator == (const SignedVector &v) const {
+  return (const Vector &)(*this) == (const Vector &)(v) && negative == v.negative;
+}
+inline bool SignedVector::operator != (const SignedVector &v) const {
+  return !(*this == v);
+}
+inline const SignedVector SignedVector::operator- (void) const {
+  return SignedVector (-(const Vector &)(*this), !negative);
+}
+
+
+/* Line */
+
+inline const Point Line::operator+ (const Line &l) const {
+  double det = n.dx * l.n.dy - n.dy * l.n.dx;
+  if (!det)
+    return Point (GLYPHY_INFINITY, GLYPHY_INFINITY);
+  return Point ((c * l.n.dy - n.dy * l.c) / det,
+                       (n.dx * l.c - c * l.n.dx) / det);
+}
+inline const SignedVector Line::operator- (const Point &p) const {
+  double mag = -(n * Vector (p) - c) / n.len ();
+  return SignedVector (n.normalized () * mag, mag < 0); /******************************************************************************************* FIX. *************************************/
+}
+
+inline const SignedVector operator- (const Point &p, const Line &l) {
+  return -(l - p);
+}
+
+inline const Line Line::normalized (void) const {
+  double d = n.len ();
+  return d ? Line (n / d, c / d) : *this;
+}
+inline const Vector Line::normal (void) const {
+  return n;
+}
+
+/* Segment */
+inline const SignedVector Segment::operator- (const Point &p) const {
+  /* shortest vector from point to line */
+  return p - Line (p1, p0); /************************************************************************************************** Should the order (p1, p0) depend on d?? ***********************/
+}
+
+/* Segment */
+inline bool Segment::contains_in_span (const Point &p) const {
+  if (p0 == p1)
+    return false;
+
+  /* shortest vector from point to line */
+  Line temp (p0, p1);
+  double mag = -(temp.n * Vector (p) - temp.c) / temp.n.len ();
+  Vector y (temp.n.normalized () * mag);
+  Point z = y + p;
+
+  // Check if z is between p0 and p1.
+
+  if (fabs (p1.y - p0.y) > fabs (p1.x - p0.x)) {
+    return ((z.y - p0.y > 0 && p1.y - p0.y > z.y - p0.y) ||
+            (z.y - p0.y < 0 && p1.y - p0.y < z.y - p0.y));
+  }
+  else {
+    return ((0 < z.x - p0.x && z.x - p0.x < p1.x - p0.x) ||
+            (0 > z.x - p0.x && z.x - p0.x > p1.x - p0.x));
+  }
+}
+
+inline double Segment::distance_to_point (const Point &p) const {
+  if (p0 == p1)
+    return 0;
+
+  // Check if z is between p0 and p1.
+  Line temp (p0, p1);
+  if (contains_in_span (p))
+    return -(temp.n * Vector (p) - temp.c) / temp.n.len ();
+
+  double dist_p_p0 = p.distance_to_point (p0);
+  double dist_p_p1 = p.distance_to_point (p1);
+  return (dist_p_p0 < dist_p_p1 ? dist_p_p0 : dist_p_p1) * (-(temp.n * Vector (p) - temp.c) < 0 ? -1 : 1);
+}
+
+
+inline double Segment::squared_distance_to_point (const Point &p) const {
+  if (p0 == p1)
+    return 0;
+
+  // Check if z is between p0 and p1.
+  Line temp (p0, p1);
+  if (contains_in_span (p))
+    return (temp.n * Vector (p) - temp.c) * (temp.n * Vector (p) - temp.c) / (temp.n * temp.n);
+
+  double dist_p_p0 = p.squared_distance_to_point (p0);
+  double dist_p_p1 = p.squared_distance_to_point (p1);
+  return (dist_p_p0 < dist_p_p1 ? dist_p_p0 : dist_p_p1);
+}
+
+
+inline double Segment::max_distance_to_arc (const Arc &a) const {
+  double max_distance = fabs(a.distance_to_point(p0)) ;
+  return  max_distance >  fabs(a.distance_to_point(p1)) ? max_distance : fabs(a.distance_to_point(p1)) ;
+}
+
+
+
+/* Arc */
+
+inline bool Arc::operator == (const Arc &a) const {
+  return p0 == a.p0 && p1 == a.p1 && d == a.d;
+}
+inline bool Arc::operator != (const Arc &a) const {
+  return !(*this == a);
+}
+
+
+inline const SignedVector Arc::operator- (const Point &p) const {
+
+  if (fabs(d) < 1e-5) {
+    Segment arc_segment (p0, p1);
+    return arc_segment - p;
+  }
+  if (wedge_contains_point (p)){
+    Vector difference = (center () - p).normalized () * fabs (p.distance_to_point (center ()) - radius ());
+
+    return SignedVector  (difference, ((p - center ()).len () < radius ()) ^ (d < 0));
+  }
+  double d0 = p.squared_distance_to_point (p0);
+  double d1 = p.squared_distance_to_point (p1);
+
+  Arc other_arc (p0, p1, (1.0 + d) / (1.0 - d));  /********************************* NOT Robust. But works? *****************/
+  Vector normal = center () - (d0 < d1 ? p0 : p1) ;
+
+  if (normal.len() == 0)
+    return SignedVector (Vector (0, 0), true);    /************************************ Check sign of this S.D. *************/
+
+  return SignedVector (Line (normal.dx, normal.dy, normal * Vector ((d0 < d1 ? p0 : p1))) - p, !other_arc.wedge_contains_point(p));
+}
+
+inline const SignedVector operator- (const Point &p, const Arc &a) {
+  return -(a - p);
+}
+
+
+
+inline double Arc::radius (void) const
+{
+  return fabs ((p1 - p0).len () / (2 * sin2atan (d)));
+}
+
+inline const Point Arc::center (void) const
+{
+  return (p0.midpoint (p1)) + (p1 - p0).ortho () / (2 * tan2atan (d));
+}
+
+inline const Pair<Vector> Arc::tangents (void) const
+{
+  Vector dp = (p1 - p0) * .5;
+  Vector pp = dp.ortho () * -sin2atan (d);
+  dp = dp * cos2atan (d);
+  return Pair<Vector> (dp + pp, dp - pp);
+}
+
+
+
+inline Bezier Arc::approximate_bezier (double *error) const
+{
+  Vector dp = p1 - p0;
+  Vector pp = dp.ortho ();
+
+  if (error)
+    *error = dp.len () * pow (fabs (d), 5) / (54 * (1 + d*d));
+
+  dp *= ((1 - d*d) / 3);
+  pp *= (2 * d / 3);
+
+  Point p0s = p0 + dp - pp;
+  Point p1s = p1 - dp - pp;
+
+  return Bezier (p0, p0s, p1s, p1);
+}
+
+
+inline bool Arc::wedge_contains_point (const Point &p) const
+{
+  Pair<Vector> t = tangents ();
+  if (fabs (d) <= 1)
+    return (p - p0) * t.first  >= 0 && (p - p1) * t.second <= 0;
+  else
+    return (p - p0) * t.first  >= 0 || (p - p1) * t.second <= 0;
+}
+
+
+/* Distance may not always be positive, but will be to an endpoint whenever necessary. */
+inline double Arc::distance_to_point (const Point &p) const {
+  if (fabs(d) < 1e-5) {
+    Segment arc_segment (p0, p1);
+    return arc_segment.distance_to_point (p);
+  }
+
+  SignedVector difference = *this - p;
+
+  if (wedge_contains_point (p) && fabs(d) > 1e-5)
+    return fabs (p.distance_to_point (center ()) - radius ()) * (difference.negative ? -1 : 1);
+  double d1 = p.squared_distance_to_point (p0);
+  double d2 = p.squared_distance_to_point (p1);
+  return (d1 < d2 ? sqrt(d1) : sqrt(d2)) * (difference.negative ? -1 : 1);
+}
+
+/* Distance will be to an endpoint whenever necessary. */
+inline double Arc::squared_distance_to_point (const Point &p) const {
+  if (fabs(d) < 1e-5) {
+    Segment arc_segment (p0, p1);
+    return arc_segment.squared_distance_to_point (p);
+  }
+
+  //SignedVector difference = *this - p;
+
+  if (wedge_contains_point (p) && fabs(d) > 1e-5) {
+    double answer = p.distance_to_point (center ()) - radius ();
+    return answer * answer;
+  }
+  double d1 = p.squared_distance_to_point (p0);
+  double d2 = p.squared_distance_to_point (p1);
+  return (d1 < d2 ? d1 : d2);
+}
+
+inline double Arc::extended_dist (const Point &p) const {
+  Point m = p0.lerp (.5, p1);
+  Vector dp = p1 - p0;
+  Vector pp = dp.ortho ();
+  float d2 = tan2atan (d);
+  if ((p - m) * (p1 - m) < 0)
+    return (p - p0) * (pp + dp * d2).normalized ();
+  else
+    return (p - p1) * (pp - dp * d2).normalized ();
+}
+
+inline void Arc::extents (glyphy_extents_t &extents) const {
+  glyphy_extents_clear (&extents);
+  glyphy_extents_add (&extents, &p0);
+  glyphy_extents_add (&extents, &p1);
+  Point c = center ();
+  double r = radius ();
+  Point p[4] = {c + r * Vector (-1,  0),
+                c + r * Vector (+1,  0),
+                c + r * Vector ( 0, -1),
+                c + r * Vector ( 0, +1)};
+  for (unsigned int i = 0; i < 4; i++)
+    if (wedge_contains_point (p[i]))
+      glyphy_extents_add (&extents, &p[i]);
+}
+
+
+/* Bezier */
+
+inline const Point Bezier::point (const double &t) const {
+  Point p01 = p0.lerp (t, p1);
+  Point p12 = p1.lerp (t, p2);
+  Point p23 = p2.lerp (t, p3);
+  Point p012 = p01.lerp (t, p12);
+  Point p123 = p12.lerp (t, p23);
+  Point p0123 = p012.lerp (t, p123);
+  return p0123;
+}
+
+inline const Point Bezier::midpoint (void) const
+{
+  Point p01 = p0.midpoint (p1);
+  Point p12 = p1.midpoint (p2);
+  Point p23 = p2.midpoint (p3);
+  Point p012 = p01.midpoint (p12);
+  Point p123 = p12.midpoint (p23);
+  Point p0123 = p012.midpoint (p123);
+  return p0123;
+}
+
+inline const Vector Bezier::tangent (const double &t) const
+{
+  double t_2_0 = t * t;
+  double t_0_2 = (1 - t) * (1 - t);
+
+  double _1__4t_1_0_3t_2_0 = 1 - 4 * t + 3 * t_2_0;
+  double _2t_1_0_3t_2_0    =     2 * t - 3 * t_2_0;
+
+  return Vector (-3 * p0.x * t_0_2
+                        +3 * p1.x * _1__4t_1_0_3t_2_0
+                        +3 * p2.x * _2t_1_0_3t_2_0
+                        +3 * p3.x * t_2_0,
+                        -3 * p0.y * t_0_2
+                        +3 * p1.y * _1__4t_1_0_3t_2_0
+                        +3 * p2.y * _2t_1_0_3t_2_0
+                        +3 * p3.y * t_2_0);
+}
+
+inline const Vector Bezier::d_tangent (const double &t) const {
+  return Vector (6 * ((-p0.x + 3*p1.x - 3*p2.x + p3.x) * t + (p0.x - 2*p1.x + p2.x)),
+                        6 * ((-p0.y + 3*p1.y - 3*p2.y + p3.y) * t + (p0.y - 2*p1.y + p2.y)));
+}
+
+inline double Bezier::curvature (const double &t) const {
+  Vector dpp = tangent (t).ortho ();
+  Vector ddp = d_tangent (t);
+  /* normal vector len squared */
+  double len = dpp.len ();
+  double curvature = (dpp * ddp) / (len * len * len);
+  return curvature;
+}
+
+inline const Pair<Bezier > Bezier::split (const double &t) const {
+  Point p01 = p0.lerp (t, p1);
+  Point p12 = p1.lerp (t, p2);
+  Point p23 = p2.lerp (t, p3);
+  Point p012 = p01.lerp (t, p12);
+  Point p123 = p12.lerp (t, p23);
+  Point p0123 = p012.lerp (t, p123);
+  return Pair<Bezier> (Bezier (p0, p01, p012, p0123),
+                       Bezier (p0123, p123, p23, p3));
+}
+
+inline const Pair<Bezier > Bezier::halve (void) const
+{
+  Point p01 = p0.midpoint (p1);
+  Point p12 = p1.midpoint (p2);
+  Point p23 = p2.midpoint (p3);
+  Point p012 = p01.midpoint (p12);
+  Point p123 = p12.midpoint (p23);
+  Point p0123 = p012.midpoint (p123);
+  return Pair<Bezier> (Bezier (p0, p01, p012, p0123),
+                       Bezier (p0123, p123, p23, p3));
+}
+
+inline const Bezier Bezier::segment (const double &t0, const double &t1) const
+{
+  Point p01 = p0.lerp (t0, p1);
+  Point p12 = p1.lerp (t0, p2);
+  Point p23 = p2.lerp (t0, p3);
+  Point p012 = p01.lerp (t0, p12);
+  Point p123 = p12.lerp (t0, p23);
+  Point p0123 = p012.lerp (t0, p123);
+
+  Point q01 = p0.lerp (t1, p1);
+  Point q12 = p1.lerp (t1, p2);
+  Point q23 = p2.lerp (t1, p3);
+  Point q012 = q01.lerp (t1, q12);
+  Point q123 = q12.lerp (t1, q23);
+  Point q0123 = q012.lerp (t1, q123);
+
+  return Bezier (p0123,
+                 p0123 + (p123 - p0123) * ((t1 - t0) / (1 - t0)),
+                 q0123 + (q012 - q0123) * ((t1 - t0) / t1),
+                 q0123);
+}
+
+} /* namespace Geometry */
+} /* namespace GLyphy */
+
+#endif /* GLYPHY_GEOMETRY_HH */
diff --git a/text/dali/internal/glyphy/glyphy-outline.cc b/text/dali/internal/glyphy/glyphy-outline.cc
new file mode 100644 (file)
index 0000000..988cc4d
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glyphy-common.hh"
+#include "glyphy-geometry.hh"
+
+using namespace GLyphy::Geometry;
+
+
+void
+glyphy_outline_reverse (glyphy_arc_endpoint_t *endpoints,
+                        unsigned int           num_endpoints)
+{
+  if (!num_endpoints)
+    return;
+
+  // Shift the d's first
+  double d0 = endpoints[0].d;
+  for (unsigned int i = 0; i < num_endpoints - 1; i++)
+    endpoints[i].d = endpoints[i + 1].d == GLYPHY_INFINITY ? GLYPHY_INFINITY : -endpoints[i + 1].d;
+  endpoints[num_endpoints - 1].d = d0;
+
+  // Reverse
+  for (unsigned int i = 0, j = num_endpoints - 1; i < j; i++, j--) {
+    glyphy_arc_endpoint_t t = endpoints[i];
+    endpoints[i] = endpoints[j];
+    endpoints[j] = t;
+  }
+}
+
+
+static bool
+winding (const glyphy_arc_endpoint_t *endpoints,
+         unsigned int                 num_endpoints)
+{
+  /*
+   * Algorithm:
+   *
+   * - Find the lowest-x part of the contour,
+   * - If the point is an endpoint:
+   *   o compare the angle of the incoming and outgoing edges of that point
+   *     to find out whether it's CW or CCW,
+   * - Otherwise, compare the y of the two endpoints of the arc with lowest-x point.
+   *
+   * Note:
+   *
+   * We can use a simpler algorithm here: Act as if arcs are lines, then use the
+   * triangle method to calculate the signed area of the contour and get the sign.
+   * It should work for all cases we care about.  The only case failing would be
+   * that of two endpoints and two arcs.  But we can even special-case that.
+   */
+
+  unsigned int corner = 1;
+  for (unsigned int i = 2; i < num_endpoints; i++)
+    if (endpoints[i].p.x < endpoints[corner].p.x ||
+        (endpoints[i].p.x == endpoints[corner].p.x &&
+         endpoints[i].p.y < endpoints[corner].p.y))
+      corner = i;
+
+  double min_x = endpoints[corner].p.x;
+  int winner = -1;
+  Point p0 (0, 0);
+  for (unsigned int i = 0; i < num_endpoints; i++) {
+    const glyphy_arc_endpoint_t &endpoint = endpoints[i];
+    if (endpoint.d == GLYPHY_INFINITY || endpoint.d == 0 /* arcs only, not lines */) {
+      p0 = endpoint.p;
+      continue;
+    }
+    Arc arc (p0, endpoint.p, endpoint.d);
+    p0 = endpoint.p;
+
+    Point c = arc.center ();
+    double r = arc.radius ();
+    if (c.x - r < min_x && arc.wedge_contains_point (c - Vector (r, 0))) {
+      min_x = c.x - r;
+      winner = i;
+    }
+  }
+
+  if (winner == -1)
+  {
+    // Corner is lowest-x.  Find the tangents of the two arcs connected to the
+    // corner and compare the tangent angles to get contour direction.
+    const glyphy_arc_endpoint_t ethis = endpoints[corner];
+    const glyphy_arc_endpoint_t eprev = endpoints[corner - 1];
+    const glyphy_arc_endpoint_t enext = endpoints[corner < num_endpoints - 1 ? corner + 1 : 1];
+    double in  = (-Arc (eprev.p, ethis.p, ethis.d).tangents ().second).angle ();
+    double out = (+Arc (ethis.p, enext.p, enext.d).tangents ().first ).angle ();
+    return out > in;
+  }
+  else
+  {
+    // Easy.
+    return endpoints[winner].d < 0;
+  }
+
+  return false;
+}
+
+
+static int
+categorize (double v, double ref)
+{
+  return v < ref - GLYPHY_EPSILON ? -1 : v > ref + GLYPHY_EPSILON ? +1 : 0;
+}
+
+static bool
+is_zero (double v)
+{
+  return fabs (v) < GLYPHY_EPSILON;
+}
+
+static bool
+even_odd (const glyphy_arc_endpoint_t *c_endpoints,
+          unsigned int                 num_c_endpoints,
+          const glyphy_arc_endpoint_t *endpoints,
+          unsigned int                 num_endpoints)
+{
+  /*
+   * Algorithm:
+   *
+   * - For a point on the contour, draw a halfline in a direction
+   *   (eg. decreasing x) to infinity,
+   * - Count how many times it crosses all other contours,
+   * - Pay special attention to points falling exactly on the halfline,
+   *   specifically, they count as +.5 or -.5, depending the direction
+   *   of crossing.
+   *
+   * All this counting is extremely tricky:
+   *
+   * - Floating point equality cannot be relied on here,
+   * - Lots of arc analysis needed,
+   * - Without having a point that we know falls /inside/ the contour,
+   *   there are legitimate cases that we simply cannot handle using
+   *   this algorithm.  For example, imagine the following glyph shape:
+   *
+   *         +---------+
+   *         | +-----+ |
+   *         |  \   /  |
+   *         |   \ /   |
+   *         +----o----+
+   *
+   *   If the glyph is defined as two outlines, and when analysing the
+   *   inner outline we happen to pick the point denoted by 'o' for
+   *   analysis, there simply is no way to differentiate this case from
+   *   the following case:
+   *
+   *         +---------+
+   *         |         |
+   *         |         |
+   *         |         |
+   *         +----o----+
+   *             / \
+   *            /   \
+   *           +-----+
+   *
+   *   However, in one, the triangle should be filled in, and in the other
+   *   filled out.
+   *
+   *   One way to work around this may be to do the analysis for all endpoints
+   *   on the outline and take majority.  But even that can fail in more
+   *   extreme yet legitimate cases, such as this one:
+   *
+   *           +--+--+
+   *           | / \ |
+   *           |/   \|
+   *           +     +
+   *           |\   /|
+   *           | \ / |
+   *           +--o--+
+   *
+   *   The only correct algorithm I can think of requires a point that falls
+   *   fully inside the outline.  While we can try finding such a point (not
+   *   dissimilar to the winding algorithm), it's beyond what I'm willing to
+   *   implement right now.
+   */
+
+  const Point p = c_endpoints[0].p;
+
+  double count = 0;
+  Point p0 (0, 0);
+  for (unsigned int i = 0; i < num_endpoints; i++) {
+    const glyphy_arc_endpoint_t &endpoint = endpoints[i];
+    if (endpoint.d == GLYPHY_INFINITY) {
+      p0 = endpoint.p;
+      continue;
+    }
+    Arc arc (p0, endpoint.p, endpoint.d);
+    p0 = endpoint.p;
+
+    /*
+     * Skip our own contour
+     */
+    if (&endpoint >= c_endpoints && &endpoint < c_endpoints + num_c_endpoints)
+      continue;
+
+    /* End-point y's compared to the ref point; lt, eq, or gt */
+    unsigned s0 = categorize (arc.p0.y, p.y);
+    unsigned s1 = categorize (arc.p1.y, p.y);
+
+    if (is_zero (arc.d))
+    {
+      /* Line */
+
+      if (!s0 || !s1)
+      {
+        /*
+         * Add +.5 / -.5 for each endpoint on the halfline, depending on
+         * crossing direction.
+         */
+        Pair<Vector> t = arc.tangents ();
+        if (!s0 && arc.p0.x < p.x + GLYPHY_EPSILON)
+          count += .5 * categorize (t.first.dy, 0);
+        if (!s1 && arc.p1.x < p.x + GLYPHY_EPSILON)
+          count += .5 * categorize (t.second.dy, 0);
+        continue;
+      }
+
+      if (s0 == s1)
+        continue; // Segment fully above or below the halfline
+
+      // Find x pos that the line segment would intersect the half-line.
+      double x = arc.p0.x + (arc.p1.x - arc.p0.x) * ((p.y - arc.p0.y) / (arc.p1.y - arc.p0.y));
+
+      if (x >= p.x - GLYPHY_EPSILON)
+        continue; // Does not intersect halfline
+
+      count++; // Add one for full crossing
+      continue;
+    }
+    else
+    {
+      /* Arc */
+
+      if (!s0 || !s1)
+      {
+        /*
+         * Add +.5 / -.5 for each endpoint on the halfline, depending on
+         * crossing direction.
+         */
+        Pair<Vector> t = arc.tangents ();
+
+        /* Arc-specific logic:
+         * If the tangent has dy==0, use the other endpoint's
+         * y value to decide which way the arc will be heading.
+         */
+        if (is_zero (t.first.dy))
+          t.first.dy  = +categorize (arc.p1.y, p.y);
+        if (is_zero (t.second.dy))
+          t.second.dy = -categorize (arc.p0.y, p.y);
+
+        if (!s0 && arc.p0.x < p.x + GLYPHY_EPSILON)
+          count += .5 * categorize (t.first.dy, 0);
+        if (!s1 && arc.p1.x < p.x + GLYPHY_EPSILON)
+          count += .5 * categorize (t.second.dy, 0);
+      }
+
+      Point c = arc.center ();
+      double r = arc.radius ();
+      if (c.x - r >= p.x)
+        continue; // No chance
+      /* Solve for arc crossing line with y = p.y */
+      double dy = p.y - c.y;
+      double x2 = r * r - dy * dy;
+      if (x2 <= GLYPHY_EPSILON)
+        continue; // Negative delta, no crossing
+      double dx = sqrt (x2);
+      /* There's two candidate points on the arc with the same y as the
+       * ref point. */
+      Point pp[2] = { Point (c.x - dx, p.y),
+                      Point (c.x + dx, p.y) };
+
+#define POINTS_EQ(a,b) (is_zero (a.x - b.x) && is_zero (a.y - b.y))
+      for (unsigned int i = 0; i < ARRAY_LENGTH (pp); i++)
+      {
+        /* Make sure we don't double-count endpoints that fall on the
+         * halfline as we already accounted for those above */
+        if (!POINTS_EQ (pp[i], arc.p0) && !POINTS_EQ (pp[i], arc.p1) &&
+            pp[i].x < p.x - GLYPHY_EPSILON && arc.wedge_contains_point (pp[i]))
+          count++; // Add one for full crossing
+      }
+#undef POINTS_EQ
+    }
+  }
+
+  return !(int (floor (count)) & 1);
+}
+
+static bool
+process_contour (glyphy_arc_endpoint_t       *endpoints,
+                 unsigned int                 num_endpoints,
+                 const glyphy_arc_endpoint_t *all_endpoints,
+                 unsigned int                 num_all_endpoints,
+                 bool                         inverse)
+{
+  /*
+   * Algorithm:
+   *
+   * - Find the winding direction and even-odd number,
+   * - If the two disagree, reverse the contour, inplace.
+   */
+
+  if (!num_endpoints)
+    return false;
+
+  if (num_endpoints < 3) {
+    abort (); // Don't expect this
+    return false; // Need at least two arcs
+  }
+  if (Point (endpoints[0].p) != Point (endpoints[num_endpoints-1].p)) {
+    abort (); // Don't expect this
+    return false; // Need a closed contour
+   }
+
+  if (inverse ^
+      winding (endpoints, num_endpoints) ^
+      even_odd (endpoints, num_endpoints, all_endpoints, num_all_endpoints))
+  {
+    glyphy_outline_reverse (endpoints, num_endpoints);
+    return true;
+  }
+
+  return false;
+}
+
+/* Returns true if outline was modified */
+glyphy_bool_t
+glyphy_outline_winding_from_even_odd (glyphy_arc_endpoint_t *endpoints,
+                                      unsigned int           num_endpoints,
+                                      glyphy_bool_t          inverse)
+{
+  /*
+   * Algorithm:
+   *
+   * - Process one contour at a time.
+   */
+
+  unsigned int start = 0;
+  bool ret = false;
+  for (unsigned int i = 1; i < num_endpoints; i++) {
+    const glyphy_arc_endpoint_t &endpoint = endpoints[i];
+    if (endpoint.d == GLYPHY_INFINITY) {
+      ret = ret | process_contour (endpoints + start, i - start, endpoints, num_endpoints, bool (inverse));
+      start = i;
+    }
+  }
+  ret = ret | process_contour (endpoints + start, num_endpoints - start, endpoints, num_endpoints, bool (inverse));
+  return ret;
+}
diff --git a/text/dali/internal/glyphy/glyphy-sdf.cc b/text/dali/internal/glyphy/glyphy-sdf.cc
new file mode 100644 (file)
index 0000000..e0aa1af
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju, Wojciech Baranowski
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glyphy-common.hh"
+#include "glyphy-geometry.hh"
+
+using namespace GLyphy::Geometry;
+
+double
+glyphy_sdf_from_arc_list (const glyphy_arc_endpoint_t *endpoints,
+                          unsigned int                 num_endpoints,
+                          const glyphy_point_t        *p,
+                          glyphy_point_t              *closest_p /* may be NULL; TBD not implemented yet */)
+{
+  Point c = *p;
+  Point p0 (0, 0);
+  Arc closest_arc (p0, p0, 0);
+  double min_dist = GLYPHY_INFINITY;
+  int side = 0;
+  for (unsigned int i = 0; i < num_endpoints; i++) {
+    const glyphy_arc_endpoint_t &endpoint = endpoints[i];
+    if (endpoint.d == GLYPHY_INFINITY) {
+      p0 = endpoint.p;
+      continue;
+    }
+    Arc arc (p0, endpoint.p, endpoint.d);
+    p0 = endpoint.p;
+
+    if (arc.wedge_contains_point (c)) {
+      double sdist = arc.distance_to_point (c); /* TODO This distance has the wrong sign.  Fix */
+      double udist = fabs (sdist) * (1 - GLYPHY_EPSILON);
+      if (udist <= min_dist) {
+        min_dist = udist;
+        side = sdist >= 0 ? -1 : +1;
+      }
+    } else {
+      double udist = std::min ((arc.p0 - c).len (), (arc.p1 - c).len ());
+      if (udist < min_dist) {
+        min_dist = udist;
+        side = 0; /* unsure */
+        closest_arc = arc;
+      } else if (side == 0 && udist == min_dist) {
+        /* If this new distance is the same as the current minimum,
+         * compare extended distances.  Take the sign from the arc
+         * with larger extended distance. */
+        double old_ext_dist = closest_arc.extended_dist (c);
+        double new_ext_dist = arc.extended_dist (c);
+
+        double ext_dist = fabs (new_ext_dist) <= fabs (old_ext_dist) ?
+                          old_ext_dist : new_ext_dist;
+
+        /* For emboldening and stuff: */
+        // min_dist = fabs (ext_dist);
+        side = ext_dist >= 0 ? +1 : -1;
+      }
+    }
+  }
+
+  if (side == 0) {
+    // Technically speaking this should not happen, but it does.  So try to fix it.
+    double ext_dist = closest_arc.extended_dist (c);
+    side = ext_dist >= 0 ? +1 : -1;
+  }
+
+  return side * min_dist;
+}
diff --git a/text/dali/internal/glyphy/glyphy.h b/text/dali/internal/glyphy/glyphy.h
new file mode 100644 (file)
index 0000000..087587b
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef GLYPHY_H
+#define GLYPHY_H
+
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int glyphy_bool_t;
+
+typedef struct {
+  double x;
+  double y;
+} glyphy_point_t;
+
+/*
+ * Geometry extents
+ */
+
+typedef struct {
+  double min_x;
+  double min_y;
+  double max_x;
+  double max_y;
+} glyphy_extents_t;
+
+void
+glyphy_extents_clear (glyphy_extents_t *extents);
+
+glyphy_bool_t
+glyphy_extents_is_empty (const glyphy_extents_t *extents);
+
+void
+glyphy_extents_add (glyphy_extents_t     *extents,
+                    const glyphy_point_t *p);
+
+void
+glyphy_extents_extend (glyphy_extents_t       *extents,
+                       const glyphy_extents_t *other);
+
+glyphy_bool_t
+glyphy_extents_includes (const glyphy_extents_t *extents,
+                         const glyphy_point_t   *p);
+
+void
+glyphy_extents_scale (glyphy_extents_t *extents,
+                      double            x_scale,
+                      double            y_scale);
+
+/*
+ * Circular arcs
+ */
+
+typedef struct {
+  glyphy_point_t p0;
+  glyphy_point_t p1;
+  double d;
+} glyphy_arc_t;
+
+/*
+ * Approximate outlines with multiple arcs
+ */
+
+typedef struct {
+  glyphy_point_t p;
+  double d;
+} glyphy_arc_endpoint_t;
+
+typedef glyphy_bool_t (*glyphy_arc_endpoint_accumulator_callback_t) (glyphy_arc_endpoint_t *endpoint,
+                                                                     void                  *user_data);
+
+typedef struct glyphy_arc_accumulator_t glyphy_arc_accumulator_t;
+
+glyphy_arc_accumulator_t *
+glyphy_arc_accumulator_create (void);
+
+void
+glyphy_arc_accumulator_destroy (glyphy_arc_accumulator_t *acc);
+
+void
+glyphy_arc_accumulator_reset (glyphy_arc_accumulator_t *acc);
+
+/* Configure accumulator */
+
+void
+glyphy_arc_accumulator_set_tolerance (glyphy_arc_accumulator_t *acc,
+                                      double                    tolerance);
+
+double
+glyphy_arc_accumulator_get_tolerance (glyphy_arc_accumulator_t *acc);
+
+void
+glyphy_arc_accumulator_set_callback (glyphy_arc_accumulator_t *acc,
+                                     glyphy_arc_endpoint_accumulator_callback_t callback,
+                                     void                     *user_data);
+
+void
+glyphy_arc_accumulator_get_callback (glyphy_arc_accumulator_t  *acc,
+                                     glyphy_arc_endpoint_accumulator_callback_t *callback,
+                                     void                     **user_data);
+
+/* Accumulation results */
+
+double
+glyphy_arc_accumulator_get_error (glyphy_arc_accumulator_t *acc);
+
+glyphy_bool_t
+glyphy_arc_accumulator_successful (glyphy_arc_accumulator_t *acc);
+
+
+/* Accumulate */
+
+void
+glyphy_arc_accumulator_move_to (glyphy_arc_accumulator_t *acc,
+                                const glyphy_point_t *p0);
+
+void
+glyphy_arc_accumulator_line_to (glyphy_arc_accumulator_t *acc,
+                                const glyphy_point_t *p1);
+
+void
+glyphy_arc_accumulator_conic_to (glyphy_arc_accumulator_t *acc,
+                                 const glyphy_point_t *p1,
+                                 const glyphy_point_t *p2);
+
+void
+glyphy_arc_accumulator_cubic_to (glyphy_arc_accumulator_t *acc,
+                                 const glyphy_point_t *p1,
+                                 const glyphy_point_t *p2,
+                                 const glyphy_point_t *p3);
+
+void
+glyphy_arc_accumulator_arc_to (glyphy_arc_accumulator_t *acc,
+                               const glyphy_point_t *p1,
+                               double                d);
+
+void
+glyphy_arc_accumulator_close_path (glyphy_arc_accumulator_t *acc);
+
+void
+glyphy_arc_list_extents (const glyphy_arc_endpoint_t *endpoints,
+                         unsigned int                 num_endpoints,
+                         glyphy_extents_t            *extents);
+
+/*
+ * Modify outlines for proper consumption
+ */
+
+void
+glyphy_outline_reverse (glyphy_arc_endpoint_t *endpoints,
+                        unsigned int           num_endpoints);
+
+/* Returns true if outline was modified */
+glyphy_bool_t
+glyphy_outline_winding_from_even_odd (glyphy_arc_endpoint_t *endpoints,
+                                      unsigned int           num_endpoints,
+                                      glyphy_bool_t          inverse);
+
+/*
+ * Encode an arc outline into binary blob for fast SDF calculation
+ */
+
+typedef Dali::TextAbstraction::VectorBlob glyphy_rgba_t;
+
+glyphy_bool_t
+glyphy_arc_list_encode_blob (const glyphy_arc_endpoint_t *endpoints,
+                             unsigned int                 num_endpoints,
+                             glyphy_rgba_t               *blob,
+                             unsigned int                 blob_size,
+                             double                       faraway,
+                             double                       avg_fetch_desired,
+                             double                      *avg_fetch_achieved,
+                             unsigned int                *output_len,
+                             unsigned int                *nominal_width,  /* 6bit */
+                             unsigned int                *nominal_height, /* 6bit */
+                             glyphy_extents_t            *extents);
+
+/*
+ * Calculate signed-distance-field from (encoded) arc list
+ */
+
+double
+glyphy_sdf_from_arc_list (const glyphy_arc_endpoint_t *endpoints,
+                          unsigned int                 num_endpoints,
+                          const glyphy_point_t        *p,
+                          glyphy_point_t              *closest_p /* may be NULL; TBD not implemented yet */);
+
+double
+glyphy_sdf_from_blob (const glyphy_rgba_t  *blob,
+                      unsigned int          nominal_width,
+                      unsigned int          nominal_height,
+                      const glyphy_point_t *p,
+                      glyphy_point_t       *closest_p /* may be NULL; TBD not implemented yet */);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GLYPHY_H */
diff --git a/text/dali/internal/glyphy/vector-font-cache.cpp b/text/dali/internal/glyphy/vector-font-cache.cpp
new file mode 100644 (file)
index 0000000..972327a
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/glyphy/vector-font-cache.h>
+
+// EXTERNAL INCLUDES
+#include <vector>
+#include <math.h>
+
+// INTERNAL INCLUDES
+#include "../glyphy/glyphy.h"
+#include "../glyphy/glyphy-freetype.h"
+
+using namespace std;
+
+namespace
+{
+
+const unsigned int INITIAL_GLYPH_CAPACITY = 50;
+const double MIN_FONT_SIZE = 10;
+
+static glyphy_bool_t
+accumulate_endpoint( glyphy_arc_endpoint_t*         endpoint,
+                     vector<glyphy_arc_endpoint_t>* endpoints )
+{
+  endpoints->push_back( *endpoint );
+  return true;
+}
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+typedef vector<VectorBlob> BlobArray;
+
+struct VectorGlyph
+{
+  /**
+   * @brief Create a vector-based glyph.
+   */
+  static VectorGlyph* New( FT_Face face,
+                           FontId fontId,
+                           GlyphIndex index,
+                           glyphy_arc_accumulator_t* accumulator )
+  {
+    VectorGlyph* newGlyph = new VectorGlyph();
+    newGlyph->blobData.resize( 1024 * 16 );
+
+    if( FT_Err_Ok != FT_Load_Glyph( face,
+                                    index,
+                                    FT_LOAD_NO_BITMAP |
+                                    FT_LOAD_NO_HINTING |
+                                    FT_LOAD_NO_AUTOHINT |
+                                    FT_LOAD_NO_SCALE |
+                                    FT_LOAD_LINEAR_DESIGN |
+                                    FT_LOAD_IGNORE_TRANSFORM))
+    {
+      DALI_LOG_ERROR( "FT_Load_Glyph failed\n" );
+      delete newGlyph;
+      return NULL;
+    }
+
+    const double upem = static_cast<double>( face->units_per_EM );
+    const double tolerance = upem * 1.0f/2048.0f;
+
+    glyphy_arc_accumulator_reset( accumulator);
+    glyphy_arc_accumulator_set_tolerance( accumulator, tolerance );
+
+    vector<glyphy_arc_endpoint_t> endpoints;
+    glyphy_arc_accumulator_set_callback( accumulator,
+                                         reinterpret_cast<glyphy_arc_endpoint_accumulator_callback_t>( accumulate_endpoint ),
+                                         &endpoints );
+
+    if( FT_Err_Ok != glyphy_freetype_outline_decompose( &face->glyph->outline, accumulator ) )
+    {
+      DALI_LOG_ERROR( "glyphy_freetype_outline_decompose failed\n" );
+      delete newGlyph;
+      return NULL;
+    }
+
+    DALI_ASSERT_DEBUG( glyphy_arc_accumulator_get_error(accumulator) <= tolerance && "glyphy_arc_accumulator_get_error > tolerance" );
+
+    if( endpoints.size() )
+    {
+      glyphy_outline_winding_from_even_odd( &endpoints[0], endpoints.size (), false );
+    }
+
+    unsigned int blobLength( 0 );
+    double averageFetchAchieved( 0.0 );
+    if (!glyphy_arc_list_encode_blob( endpoints.size() ? &endpoints[0] : NULL,
+                                      endpoints.size(),
+                                      &newGlyph->blobData[0],
+                                      newGlyph->blobData.capacity(),
+                                      upem / ( MIN_FONT_SIZE * M_SQRT2 ),
+                                      4,
+                                      &averageFetchAchieved,
+                                      &blobLength,
+                                      &newGlyph->nominalWidth,
+                                      &newGlyph->nominalHeight,
+                                      &newGlyph->extents ) )
+    {
+      DALI_LOG_ERROR( "glyphy_arc_list_encode_blob failed\n" );
+      delete newGlyph;
+      return NULL;
+    }
+    newGlyph->blobData.resize( blobLength );
+
+    glyphy_extents_scale( &newGlyph->extents, 1.0/upem, 1.0/upem );
+
+    newGlyph->glyphInfo.fontId = fontId;
+    newGlyph->glyphInfo.index  = index;
+
+    if( glyphy_extents_is_empty( &newGlyph->extents ) )
+    {
+      newGlyph->glyphInfo.width  = 0.0f;
+      newGlyph->glyphInfo.height = 0.0f;
+
+      newGlyph->glyphInfo.xBearing = 0.0f;
+      newGlyph->glyphInfo.yBearing = 0.0f;
+    }
+    else
+    {
+      newGlyph->glyphInfo.width  = (newGlyph->extents.max_x - newGlyph->extents.min_x);
+      newGlyph->glyphInfo.height = (newGlyph->extents.max_y - newGlyph->extents.min_y);
+
+      newGlyph->glyphInfo.xBearing = newGlyph->extents.min_x;
+      newGlyph->glyphInfo.yBearing = newGlyph->glyphInfo.height + (newGlyph->extents.min_y);
+    }
+
+    newGlyph->glyphInfo.advance = face->glyph->metrics.horiAdvance / upem;
+    newGlyph->glyphInfo.scaleFactor = 0.0f;
+
+    return newGlyph;
+  }
+
+  VectorGlyph()
+  : advance( 0.0 ),
+    nominalWidth( 0 ),
+    nominalHeight( 0 ),
+    glyphInfo(),
+    blobData()
+  {
+    glyphy_extents_clear( &extents );
+  }
+
+  glyphy_extents_t extents;
+  double           advance;
+  unsigned int     nominalWidth;
+  unsigned int     nominalHeight;
+  GlyphInfo        glyphInfo;
+  BlobArray        blobData;
+};
+
+typedef vector<VectorGlyph*> GlyphCache;
+
+struct VectorFont
+{
+  VectorFont( FT_Face face )
+  : mFace( face ),
+    mGlyphCache()
+  {
+    mGlyphCache.reserve( INITIAL_GLYPH_CAPACITY );
+  }
+
+  FT_Face    mFace;
+  GlyphCache mGlyphCache;
+};
+
+struct VectorFontCache::Impl
+{
+  Impl( FT_Library freeTypeLibrary )
+  : mFreeTypeLibrary( freeTypeLibrary ),
+    mIdLookup(),
+    mVectorFonts(),
+    mAccumulator( NULL )
+  {
+    mAccumulator = glyphy_arc_accumulator_create();
+  }
+
+  ~Impl()
+  {
+    glyphy_arc_accumulator_destroy( mAccumulator );
+  }
+
+  FT_Library mFreeTypeLibrary; ///< A handle to a FreeType library instance.
+
+  vector<string> mIdLookup;
+
+  vector<VectorFont*> mVectorFonts;
+
+  glyphy_arc_accumulator_t* mAccumulator;
+};
+
+VectorFontCache::VectorFontCache( FT_Library freeTypeLibrary )
+: mImpl( NULL )
+{
+  mImpl = new Impl( freeTypeLibrary );
+}
+
+VectorFontCache::~VectorFontCache()
+{
+  delete mImpl;
+}
+
+FontId VectorFontCache::GetFontId( const std::string& url )
+{
+  FontId id( 0 );
+
+  if( mImpl )
+  {
+    if( ! FindFont( url, id ) )
+    {
+      id = CreateFont( url );
+    }
+  }
+
+  return id;
+}
+
+void VectorFontCache::GetGlyphMetrics( FontId vectorFontId, GlyphInfo& glyphInfo )
+{
+  if( mImpl )
+  {
+    if( vectorFontId > 0 &&
+        vectorFontId-1 < mImpl->mVectorFonts.size() )
+    {
+      VectorFont* font = mImpl->mVectorFonts[ vectorFontId-1 ];
+      GlyphCache& cache = font->mGlyphCache;
+
+      bool foundGlyph( false );
+      unsigned int foundIndex( 0 );
+      for( unsigned int i=0; i<cache.size(); ++i )
+      {
+        VectorGlyph* glyph = cache[i];
+
+        if( glyph->glyphInfo.index == glyphInfo.index )
+        {
+          foundIndex = i;
+          foundGlyph = true;
+          break;
+        }
+      }
+
+      if( foundGlyph )
+      {
+        VectorGlyph* glyph = cache[foundIndex];
+        // Note - this clobbers the original fontId, but helps avoid duplicating identical blobs
+        // e.g. if when the same font family is requested in different point-sizes
+        glyphInfo = glyph->glyphInfo;
+      }
+      else
+      {
+        VectorGlyph* newGlyph = VectorGlyph::New( font->mFace,
+                                                  glyphInfo.fontId,
+                                                  glyphInfo.index,
+                                                  mImpl->mAccumulator );
+
+        if( newGlyph )
+        {
+          glyphInfo = newGlyph->glyphInfo;
+
+          cache.push_back( newGlyph );
+        }
+      }
+    }
+  }
+}
+
+void VectorFontCache::GetVectorBlob( FontId vectorFontId,
+                                     FontId fontId,
+                                     GlyphIndex glyphIndex,
+                                     VectorBlob*& blob,
+                                     unsigned int& blobLength,
+                                     unsigned int& nominalWidth,
+                                     unsigned int& nominalHeight )
+{
+  if( mImpl )
+  {
+    if( vectorFontId > 0 &&
+        vectorFontId-1 < mImpl->mVectorFonts.size() )
+    {
+      VectorFont* font = mImpl->mVectorFonts[ vectorFontId-1 ];
+      GlyphCache& cache = font->mGlyphCache;
+
+      bool foundGlyph( false );
+      unsigned int foundIndex( 0 );
+      for( unsigned int i=0; i<cache.size(); ++i )
+      {
+        VectorGlyph* glyph = cache[i];
+
+        if( glyph->glyphInfo.index == glyphIndex )
+        {
+          foundIndex = i;
+          foundGlyph = true;
+          break;
+        }
+      }
+
+      if( foundGlyph )
+      {
+        VectorGlyph* glyph = cache[foundIndex];
+
+        blob          = &glyph->blobData[0];
+        blobLength    = glyph->blobData.size();
+        nominalWidth  = glyph->nominalWidth;
+        nominalHeight = glyph->nominalHeight;
+      }
+      else
+      {
+        VectorGlyph* newGlyph = VectorGlyph::New( font->mFace, fontId, glyphIndex, mImpl->mAccumulator );
+
+        if( newGlyph )
+        {
+          blob          = &newGlyph->blobData[0];
+          blobLength    = newGlyph->blobData.size();
+          nominalWidth  = newGlyph->nominalWidth;
+          nominalHeight = newGlyph->nominalHeight;
+
+          cache.push_back( newGlyph );
+        }
+      }
+    }
+  }
+}
+
+bool VectorFontCache::FindFont( const string& url, FontId& vectorFontId ) const
+{
+  vectorFontId = 0u;
+
+  const vector<string>& idLookup = mImpl->mIdLookup;
+
+  for( unsigned int i=0; i<idLookup.size(); ++i, ++vectorFontId )
+  {
+    if( url == idLookup[i] )
+    {
+      ++vectorFontId;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+FontId VectorFontCache::CreateFont( const string& url )
+{
+  FontId id( 0 );
+
+  // Create & cache new font face
+  FT_Face face;
+  int error = FT_New_Face( mImpl->mFreeTypeLibrary,
+                           url.c_str(),
+                           0,
+                           &face );
+
+  if( FT_Err_Ok == error )
+  {
+    mImpl->mIdLookup.push_back( url );
+    id = mImpl->mIdLookup.size();
+
+    VectorFont* newFont = new VectorFont( face );
+    mImpl->mVectorFonts.push_back( newFont );
+
+    DALI_ASSERT_DEBUG( mImpl->mIdLookup.size() == mImpl->mVectorFonts.size() );
+  }
+
+  return id;
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/internal/glyphy/vector-font-cache.h b/text/dali/internal/glyphy/vector-font-cache.h
new file mode 100644 (file)
index 0000000..91fa2e4
--- /dev/null
@@ -0,0 +1,125 @@
+#ifndef __DALI_INTERNAL_TEXT_ABSTRACTION_VECTOR_FONT_CACHE_H__
+#define __DALI_INTERNAL_TEXT_ABSTRACTION_VECTOR_FONT_CACHE_H__
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * A cache of vector-based font data.
+ */
+class VectorFontCache
+{
+public:
+
+  /**
+   * Constructor
+   */
+  VectorFontCache( FT_Library freeTypeLibrary );
+
+  /**
+   * Destructor
+   */
+  ~VectorFontCache();
+
+  /**
+   * @brief Get the font ID for a vector-based font.
+   *
+   * @param[in] url The path to the font file.
+   * @return A valid font ID, or zero if the font does not exist.
+   */
+  FontId GetFontId( const std::string& url );
+
+  /**
+   * @brief Get the unscaled metrics for a glyph.
+   *
+   * @param[in] vectorFontId The font ID for a vector-based font.
+   * @param[in,out] array A glyph-info structure with initialized FontId & GlyphIndex value.
+   * On return the size, bearing and advance values will be set.
+   */
+  void GetGlyphMetrics( FontId vectorFontId, GlyphInfo& glyph_info );
+
+  /**
+   * @brief Get the vector representation of a glyph.
+   *
+   * @param[in] vectorFontId The font ID for a vector-based font.
+   * @param[in] fontId The equivalent font ID.
+   * @param[in] glyphIndex The index of a glyph within the specified font.
+   * @param[out] blob A blob of data; this is owned by VectorFontCache and should be copied by the caller of GetVectorBlob().
+   * @param[out] blobLength The length of the blob data, or zero if the blob creation failed.
+   * @param[out] nominalWidth The width of the blob.
+   * @param[out] nominalHeight The height of the blob.
+   */
+  void GetVectorBlob( FontId vectorFontId, FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight );
+
+private:
+
+  /**
+   * @brief Get the font ID for a vector-based font.
+   *
+   * @param[in] url The path to the font file.
+   * @param[out] fontId A valid font ID, or zero if the font does not exist.
+   * @return True if the font was found.
+   */
+  bool FindFont( const std::string& url, FontId& fontId ) const;
+
+  /**
+   * @brief Add a new vector-based font to the cache.
+   *
+   * @param[in] url The path to the font file.
+   * @return A valid font ID, or zero if the font does not exist.
+   */
+  FontId CreateFont( const std::string& url );
+
+  // Undefined copy constructor.
+  VectorFontCache( const VectorFontCache& );
+
+  // Undefined assignment constructor.
+  VectorFontCache& operator=( VectorFontCache& );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TEXT_ABSTRACTION_VECTOR_FONT_CACHE_H__
index 2521dd6..dbf4076 100644 (file)
@@ -203,11 +203,11 @@ GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
   return mPlugin->GetGlyphIndex( fontId, charcode );
 }
 
-bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal, int desiredFixedSize )
+bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal, int desiredFixedSize )
 {
   CreatePlugin();
 
-  return mPlugin->GetGlyphMetrics( array, size, horizontal, desiredFixedSize );
+  return mPlugin->GetGlyphMetrics( array, size, type, horizontal, desiredFixedSize );
 }
 
 BufferImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
@@ -217,6 +217,13 @@ BufferImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
   return mPlugin->CreateBitmap( fontId, glyphIndex );
 }
 
+void FontClient::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
+{
+  CreatePlugin();
+
+  return mPlugin->CreateVectorBlob( fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
+}
+
 const GlyphInfo& FontClient::GetEllipsisGlyph( PointSize26Dot6 pointSize )
 {
   CreatePlugin();
index 74edd11..aea274c 100644 (file)
@@ -151,7 +151,7 @@ public:
   /**
    * @copydoc Dali::FontClient::GetGlyphMetrics()
    */
-  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal, int desiredFixedSize );
+  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal, int desiredFixedSize );
 
   /**
    * @copydoc Dali::FontClient::CreateBitmap()
@@ -159,6 +159,11 @@ public:
   BufferImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex );
 
   /**
+   * @copydoc Dali::FontClient::CreateVectorBlob()
+   */
+  void CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight );
+
+  /**
    * @copydoc Dali::FontClient::GetEllipsisGlyph()
    */
   const GlyphInfo& GetEllipsisGlyph( PointSize26Dot6 pointSize );
index 41bd899..d1ea359 100644 (file)
@@ -169,6 +169,7 @@ FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
   mMetrics( metrics ),
   mFixedWidthPixels( 0.0f ),
   mFixedHeightPixels( 0.0f ),
+  mVectorFontId( 0 ),
   mIsFixedSizeBitmap( false )
 {
 }
@@ -187,6 +188,7 @@ FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
   mMetrics( metrics ),
   mFixedWidthPixels( fixedWidth ),
   mFixedHeightPixels( fixedHeight ),
+  mVectorFontId( 0 ),
   mIsFixedSizeBitmap( true )
 {
 }
@@ -203,6 +205,7 @@ FontClient::Plugin::Plugin( unsigned int horizontalDpi,
   mValidatedFontCache(),
   mFontDescriptionCache( 1u ),
   mFontIdCache(),
+  mVectorFontCache( NULL ),
   mEllipsisCache(),
   mDefaultFontDescriptionCached( false )
 {
@@ -211,6 +214,10 @@ FontClient::Plugin::Plugin( unsigned int horizontalDpi,
   {
     DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
   }
+
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+  mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
+#endif
 }
 
 FontClient::Plugin::~Plugin()
@@ -228,6 +235,10 @@ FontClient::Plugin::~Plugin()
     }
   }
 
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+  delete mVectorFontCache;
+#endif
+
   FT_Done_FreeType( mFreeTypeLibrary );
 }
 
@@ -707,9 +718,23 @@ GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
 
 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
                                           uint32_t size,
+                                          GlyphType type,
                                           bool horizontal,
                                           int desiredFixedSize )
 {
+  if( VECTOR_GLYPH == type )
+  {
+    return GetVectorMetrics( array, size, horizontal, desiredFixedSize );
+  }
+
+  return GetBitmapMetrics( array, size, horizontal, desiredFixedSize );
+}
+
+bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
+                                           uint32_t size,
+                                           bool horizontal,
+                                           int desiredFixedSize )
+{
   bool success( true );
 
   for( unsigned int i=0; i<size; ++i )
@@ -791,6 +816,50 @@ bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
   return success;
 }
 
+bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
+                                           uint32_t size,
+                                           bool horizontal,
+                                           int desiredFixedSize )
+{
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+  bool success( true );
+
+  for( unsigned int i=0; i<size; ++i )
+  {
+    FontId fontId = array[i].fontId;
+
+    if( fontId > 0 &&
+        fontId-1 < mFontCache.size() )
+    {
+      CacheItem& font = mFontCache[fontId-1];
+
+      if( ! font.mVectorFontId )
+      {
+        font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
+      }
+
+      mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
+
+      // Vector metrics are in EMs, convert to pixels
+      float scale = (static_cast<float>(font.mPointSize)/64.0f) * mDpiVertical/72.0f;
+      array[i].width    *= scale;
+      array[i].height   *= scale;
+      array[i].xBearing *= scale;
+      array[i].yBearing *= scale;
+      array[i].advance  *= scale;
+    }
+    else
+    {
+      success = false;
+    }
+  }
+
+  return success;
+#else
+  return false;
+#endif
+}
+
 BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
                                               GlyphIndex glyphIndex )
 {
@@ -853,6 +922,27 @@ BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
   return bitmap;
 }
 
+void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
+{
+  blob = NULL;
+  blobLength = 0;
+
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+  if( fontId > 0 &&
+      fontId-1 < mFontCache.size() )
+  {
+    CacheItem& font = mFontCache[fontId-1];
+
+    if( ! font.mVectorFontId )
+    {
+      font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
+    }
+
+    mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
+  }
+#endif
+}
+
 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 pointSize )
 {
   // First look into the cache if there is an ellipsis glyph for the requested point size.
@@ -885,7 +975,7 @@ const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 pointSize
   item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
                                         ELLIPSIS_CHARACTER );
 
-  GetGlyphMetrics( &item.glyph, 1u, true, 0 );
+  GetBitmapMetrics( &item.glyph, 1u, true, 0 );
 
   return item.glyph;
 }
index 65cd9e5..d43e350 100644 (file)
 #include <dali/devel-api/text-abstraction/glyph-info.h>
 #include <dali/internal/text-abstraction/font-client-impl.h>
 
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+#include <dali/internal/glyphy/vector-font-cache.h>
+#else
+class VectorFontCache;
+#endif
+
 // EXTERNAL INCLUDES
 #include <ft2build.h>
 #include FT_FREETYPE_H
@@ -114,6 +120,7 @@ struct FontClient::Plugin
     FontMetrics mMetrics;        ///< The font metrics.
     FT_Short mFixedWidthPixels;  ///< The height in pixels (fixed size bitmaps only)
     FT_Short mFixedHeightPixels; ///< The height in pixels (fixed size bitmaps only)
+    unsigned int mVectorFontId;  ///< The ID of the equivalent vector-based font
     bool mIsFixedSizeBitmap;     ///< Whether the font has fixed size bitmaps.
   };
 
@@ -247,7 +254,17 @@ struct FontClient::Plugin
   /**
    * @copydoc Dali::FontClient::GetGlyphMetrics()
    */
-  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal, int desiredFixedSize );
+  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal, int desiredFixedSize );
+
+  /**
+   * Helper for GetGlyphMetrics when using bitmaps
+   */
+  bool GetBitmapMetrics( GlyphInfo* array, uint32_t size, bool horizontal, int desiredFixedSize );
+
+  /**
+   * Helper for GetGlyphMetrics when using vectors
+   */
+  bool GetVectorMetrics( GlyphInfo* array, uint32_t size, bool horizontal, int desiredFixedSize );
 
   /**
    * @copydoc Dali::FontClient::CreateBitmap()
@@ -255,6 +272,11 @@ struct FontClient::Plugin
   BufferImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex );
 
   /**
+   * @copydoc Dali::FontClient::CreateVectorBlob()
+   */
+  void CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight );
+
+  /**
    * @copydoc Dali::FontClient::GetEllipsisGlyph()
    */
   const GlyphInfo& GetEllipsisGlyph( PointSize26Dot6 pointSize );
@@ -437,6 +459,8 @@ private:
   FontList                              mFontDescriptionCache; ///< Caches font descriptions for the validated font.
   std::vector<FontIdCacheItem>          mFontIdCache;          ///< Caches font ids for the pairs of font point size and the index to the vector with font descriptions of the validated fonts.
 
+  VectorFontCache* mVectorFontCache; ///< Separate cache for vector data blobs etc.
+
   Vector<EllipsisItem> mEllipsisCache;      ///< Caches ellipsis glyphs for a particular point size.
 
   bool mDefaultFontDescriptionCached : 1; ///< Whether the default font is cached or not