Vector-based text rendering 86/56486/29
authorPaul Wisbey <p.wisbey@samsung.com>
Mon, 30 Nov 2015 13:48:04 +0000 (13:48 +0000)
committerPaul Wisbey <p.wisbey@samsung.com>
Wed, 20 Apr 2016 17:49:11 +0000 (18:49 +0100)
Change-Id: Ieadbb0e545219f8184fe50bb6f00bfaced902184

21 files changed:
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
build/tizen/configure.ac
build/tizen/dali-toolkit/Makefile.am
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/text/metrics.h
dali-toolkit/internal/text/rendering/text-backend-impl.cpp
dali-toolkit/internal/text/rendering/vector-based/file.list [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-common-glsl.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-sdf-glsl.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h [new file with mode: 0644]
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h
dali-toolkit/public-api/text/rendering-backend.h

index 5e77ebb..9378648 100644 (file)
@@ -280,3 +280,44 @@ int UtcDaliToolkitTextLabelLanguagesP(void)
 
   END_TEST;
 }
 
   END_TEST;
 }
+
+int UtcDaliToolkitTextLabelVectorBasedP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelVectorBasedP");
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  glAbstraction.EnableTextureCallTrace( true );
+
+  TextLabel label = TextLabel::New();
+  label.SetParentOrigin( ParentOrigin::CENTER );
+  label.SetSize( Stage::GetCurrent().GetSize() );
+  label.SetProperty( TextLabel::Property::TEXT, "Hello World" );
+  label.SetProperty( TextLabel::Property::POINT_SIZE, 10.0f );
+  label.SetProperty( TextLabel::Property::RENDERING_BACKEND, Toolkit::Text::RENDERING_VECTOR_BASED );
+  Stage::GetCurrent().Add( label );
+
+  application.SendNotification();
+  application.Render();
+
+  // Test that the vector data is uploaded to atlas
+  DALI_TEST_CHECK( glAbstraction.GetTextureTrace().FindMethod("TexSubImage2D") );
+  glAbstraction.GetTextureTrace().Reset();
+
+  // Add another label with the same text in a different point-size
+  TextLabel label2 = TextLabel::New();
+  label2.SetProperty( TextLabel::Property::TEXT, "Hello World" );
+  label2.SetProperty( TextLabel::Property::POINT_SIZE, 13.0f );
+  label2.SetProperty( TextLabel::Property::RENDERING_BACKEND, Toolkit::Text::RENDERING_VECTOR_BASED );
+  Stage::GetCurrent().Add( label2 );
+
+  application.SendNotification();
+  application.Render();
+
+  // Test that no additional vector data was uploaded to atlas
+  // i.e. the same vector data can be used to render any point-size
+  DALI_TEST_CHECK( ! glAbstraction.GetTextureTrace().FindMethod("TexSubImage2D") );
+
+  END_TEST;
+}
+
index 1fa0845..a861a17 100644 (file)
@@ -142,6 +142,9 @@ fi
 #set a variable for the makefile to force compile the JAvaSplugin
 AM_CONDITIONAL([ENABLE_JAVASCRIPT_PLUGIN], [test x$build_javascript_plugin = xyes])
 
 #set a variable for the makefile to force compile the JAvaSplugin
 AM_CONDITIONAL([ENABLE_JAVASCRIPT_PLUGIN], [test x$build_javascript_plugin = xyes])
 
+# Platforms with highp shader support can use vector based text
+AM_CONDITIONAL([ENABLE_VECTOR_BASED_TEXT_RENDERING], [test x$dali_profile = xUBUNTU])
+
 AC_SUBST(dataReadWriteDir)
 AC_SUBST(dataReadOnlyDir)
 AC_SUBST(DALI_TOOLKIT_CFLAGS)
 AC_SUBST(dataReadWriteDir)
 AC_SUBST(dataReadOnlyDir)
 AC_SUBST(DALI_TOOLKIT_CFLAGS)
index a760d27..f803a93 100644 (file)
@@ -32,6 +32,14 @@ include ../../../dali-toolkit/internal/file.list
 include ../../../dali-toolkit/public-api/file.list
 include ../../../dali-toolkit/devel-api/file.list
 
 include ../../../dali-toolkit/public-api/file.list
 include ../../../dali-toolkit/devel-api/file.list
 
+vector_based_text_src_dir = ../../../dali-toolkit/internal/text/rendering/vector-based
+include ../../../dali-toolkit/internal/text/rendering/vector-based/file.list
+
+if ENABLE_VECTOR_BASED_TEXT_RENDERING
+toolkit_src_files += $(vector_based_text_src_files)
+DALI_TOOLKIT_CFLAGS += -DENABLE_VECTOR_BASED_TEXT_RENDERING
+endif
+
 resources_dir = ../../../resources
 daliimagedir = ${dataReadOnlyDir}/toolkit/images/
 daliimage_DATA = ${dali_toolkit_image_files}
 resources_dir = ../../../resources
 daliimagedir = ${dataReadOnlyDir}/toolkit/images/
 daliimage_DATA = ${dali_toolkit_image_files}
index 981b228..082e7e5 100644 (file)
@@ -164,11 +164,23 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
         int backend = value.Get< int >();
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p RENDERING_BACKEND %d\n", impl.mController.Get(), backend );
 
         int backend = value.Get< int >();
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p RENDERING_BACKEND %d\n", impl.mController.Get(), backend );
 
+#ifndef ENABLE_VECTOR_BASED_TEXT_RENDERING
+        if( Text::RENDERING_VECTOR_BASED == backend )
+        {
+          backend = TextAbstraction::BITMAP_GLYPH; // Fallback to bitmap-based rendering
+        }
+#endif
         if( impl.mRenderingBackend != backend )
         {
           impl.mRenderingBackend = backend;
           impl.mRenderer.Reset();
         if( impl.mRenderingBackend != backend )
         {
           impl.mRenderingBackend = backend;
           impl.mRenderer.Reset();
-          impl.RequestTextRelayout();
+
+          if( impl.mController )
+          {
+            // When using the vector-based rendering, the size of the GLyphs are different
+            TextAbstraction::GlyphType glyphType = (Text::RENDERING_VECTOR_BASED == impl.mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
+            impl.mController->SetGlyphType( glyphType );
+          }
         }
         break;
       }
         }
         break;
       }
@@ -972,6 +984,10 @@ void TextField::OnInitialize()
 
   mController = Text::Controller::New( *this );
 
 
   mController = Text::Controller::New( *this );
 
+  // When using the vector-based rendering, the size of the GLyphs are different
+  TextAbstraction::GlyphType glyphType = (Text::RENDERING_VECTOR_BASED == mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
+  mController->SetGlyphType( glyphType );
+
   mDecorator = Text::Decorator::New( *mController,
                                      *mController );
 
   mDecorator = Text::Decorator::New( *mController,
                                      *mController );
 
index 7ad0bfb..9d3fd45 100644 (file)
@@ -125,13 +125,25 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
     {
       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
       {
     {
       case Toolkit::TextLabel::Property::RENDERING_BACKEND:
       {
-        const int backend = value.Get< int >();
+        int backend = value.Get< int >();
 
 
+#ifndef ENABLE_VECTOR_BASED_TEXT_RENDERING
+        if( Text::RENDERING_VECTOR_BASED == backend )
+        {
+          backend = TextAbstraction::BITMAP_GLYPH; // Fallback to bitmap-based rendering
+        }
+#endif
         if( impl.mRenderingBackend != backend )
         {
           impl.mRenderingBackend = backend;
           impl.mRenderer.Reset();
         if( impl.mRenderingBackend != backend )
         {
           impl.mRenderingBackend = backend;
           impl.mRenderer.Reset();
-          impl.RequestTextRelayout();
+
+          if( impl.mController )
+          {
+            // When using the vector-based rendering, the size of the GLyphs are different
+            TextAbstraction::GlyphType glyphType = (Text::RENDERING_VECTOR_BASED == impl.mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
+            impl.mController->SetGlyphType( glyphType );
+          }
         }
         break;
       }
         }
         break;
       }
@@ -455,6 +467,10 @@ void TextLabel::OnInitialize()
 
   mController = Text::Controller::New( *this );
 
 
   mController = Text::Controller::New( *this );
 
+  // When using the vector-based rendering, the size of the GLyphs are different
+  TextAbstraction::GlyphType glyphType = (Text::RENDERING_VECTOR_BASED == mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
+  mController->SetGlyphType( glyphType );
+
   // Use height-for-width negotiation by default
   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
   self.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
   // Use height-for-width negotiation by default
   self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
   self.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
index 147ae79..5e58f38 100644 (file)
@@ -50,6 +50,16 @@ public:
   }
 
   /**
   }
 
   /**
+   * @brief Used to switch between bitmap & vector based glyphs
+   *
+   * @param[in] glyphType The type of glyph; note that metrics for bitmap & vector based glyphs are different.
+   */
+  void SetGlyphType( TextAbstraction::GlyphType glyphType )
+  {
+    mGlyphType = glyphType;
+  }
+
+  /**
    * @brief Set the maximum Emoji size.
    *
    * @param[in] emojiSize Emoticons will be scaled to fit this size in pixels.
    * @brief Set the maximum Emoji size.
    *
    * @param[in] emojiSize Emoticons will be scaled to fit this size in pixels.
@@ -91,7 +101,7 @@ public:
    */
   bool GetGlyphMetrics( GlyphInfo* array, uint32_t size )
   {
    */
   bool GetGlyphMetrics( GlyphInfo* array, uint32_t size )
   {
-    return mFontClient.GetGlyphMetrics( array, size, true, mEmojiSize ); // inline for performance
+    return mFontClient.GetGlyphMetrics( array, size, mGlyphType, true, mEmojiSize ); // inline for performance
   }
 
 protected:
   }
 
 protected:
@@ -108,6 +118,7 @@ private:
    */
   Metrics( TextAbstraction::FontClient& fontClient )
   : mFontClient( fontClient ),
    */
   Metrics( TextAbstraction::FontClient& fontClient )
   : mFontClient( fontClient ),
+    mGlyphType( TextAbstraction::BITMAP_GLYPH ),
     mEmojiSize( 0 )
   {
   }
     mEmojiSize( 0 )
   {
   }
@@ -121,7 +132,7 @@ private:
 private:
 
   TextAbstraction::FontClient mFontClient;
 private:
 
   TextAbstraction::FontClient mFontClient;
-
+  TextAbstraction::GlyphType mGlyphType;
   int mEmojiSize;
 };
 
   int mEmojiSize;
 };
 
index 776d408..10602c7 100644 (file)
@@ -25,6 +25,9 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/text/rendering-backend.h>
 #include <dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h>
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/text/rendering-backend.h>
 #include <dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h>
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+#include <dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.h>
+#endif
 
 namespace Dali
 {
 
 namespace Dali
 {
@@ -91,6 +94,16 @@ RendererPtr Backend::NewRenderer( unsigned int renderingType )
     }
     break;
 
     }
     break;
 
+    case Dali::Toolkit::Text::RENDERING_VECTOR_BASED:
+    {
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+      renderer = Dali::Toolkit::Text::VectorBasedRenderer::New();
+#else
+      renderer = Dali::Toolkit::Text::AtlasRenderer::New(); // Fallback to bitmap-based rendering
+#endif
+    }
+    break;
+
     default:
     {
       DALI_LOG_WARNING( "Unknown renderer type: %d", renderingType );
     default:
     {
       DALI_LOG_WARNING( "Unknown renderer type: %d", renderingType );
diff --git a/dali-toolkit/internal/text/rendering/vector-based/file.list b/dali-toolkit/internal/text/rendering/vector-based/file.list
new file mode 100644 (file)
index 0000000..0772a37
--- /dev/null
@@ -0,0 +1,7 @@
+# Add local source files here
+
+vector_based_text_src_files = \
+   $(vector_based_text_src_dir)/vector-based-renderer.cpp \
+   $(vector_based_text_src_dir)/vector-blob-atlas.cpp \
+   $(vector_based_text_src_dir)/vector-blob-atlas-share.cpp \
+   $(vector_based_text_src_dir)/glyphy-shader/glyphy-shader.cpp
diff --git a/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-common-glsl.h b/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-common-glsl.h
new file mode 100644 (file)
index 0000000..a3a1a30
--- /dev/null
@@ -0,0 +1,231 @@
+static const char *glyphy_common_glsl =
+"/*\n"
+" * Copyright 2012 Google, Inc. All Rights Reserved.\n"
+" *\n"
+" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
+" * you may not use this file except in compliance with the License.\n"
+" * You may obtain a copy of the License at\n"
+" *\n"
+" *     http://www.apache.org/licenses/LICENSE-2.0\n"
+" *\n"
+" * Unless required by applicable law or agreed to in writing, software\n"
+" * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
+" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
+" * See the License for the specific language governing permissions and\n"
+" * limitations under the License.\n"
+" *\n"
+" * Google Author(s): Behdad Esfahbod, Maysum Panju\n"
+" */\n"
+"\n"
+"\n"
+"#ifndef GLYPHY_INFINITY\n"
+"#  define GLYPHY_INFINITY 1e9\n"
+"#endif\n"
+"#ifndef GLYPHY_EPSILON\n"
+"#  define GLYPHY_EPSILON  1e-5\n"
+"#endif\n"
+"\n"
+"#ifndef GLYPHY_RGBA\n"
+"#  ifdef GLYPHY_BGRA\n"
+"#    define GLYPHY_RGBA(v) glyphy_bgra (v)\n"
+"#  else\n"
+"#    define GLYPHY_RGBA(v) glyphy_rgba (v)\n"
+"#  endif\n"
+"#endif\n"
+"\n"
+"vec4\n"
+"glyphy_rgba (const vec4 v)\n"
+"{\n"
+"  return v.rgba;\n"
+"}\n"
+"\n"
+"vec4\n"
+"glyphy_bgra (const vec4 v)\n"
+"{\n"
+"  return v.bgra;\n"
+"}\n"
+"\n"
+"\n"
+"struct glyphy_arc_t {\n"
+"  vec2  p0;\n"
+"  vec2  p1;\n"
+"  float d;\n"
+"};\n"
+"\n"
+"struct glyphy_arc_endpoint_t {\n"
+"  /* Second arc endpoint */\n"
+"  vec2  p;\n"
+"  /* Infinity if this endpoint does not form an arc with the previous\n"
+"   * endpoint.  Ie. a \"move_to\".  Test with glyphy_isinf().\n"
+"   * Arc depth otherwise.  */\n"
+"  float d;\n"
+"};\n"
+"\n"
+"struct glyphy_arc_list_t {\n"
+"  /* Number of endpoints in the list.\n"
+"   * Will be zero if we're far away inside or outside, in which case side is set.\n"
+"   * Will be -1 if this arc-list encodes a single line, in which case line_* are set. */\n"
+"  int num_endpoints;\n"
+"\n"
+"  /* If num_endpoints is zero, this specifies whether we are inside (-1)\n"
+"   * or outside (+1).  Otherwise we're unsure (0). */\n"
+"  int side;\n"
+"  /* Offset to the arc-endpoints from the beginning of the glyph blob */\n"
+"  int offset;\n"
+"\n"
+"  /* A single line is all we care about.  It's right here. */\n"
+"  float line_angle;\n"
+"  float line_distance; /* From nominal glyph center */\n"
+"};\n"
+"\n"
+"bool\n"
+"glyphy_isinf (const float v)\n"
+"{\n"
+"  return abs (v) >= GLYPHY_INFINITY * .5;\n"
+"}\n"
+"\n"
+"bool\n"
+"glyphy_iszero (const float v)\n"
+"{\n"
+"  return abs (v) <= GLYPHY_EPSILON * 2.;\n"
+"}\n"
+"\n"
+"vec2\n"
+"glyphy_ortho (const vec2 v)\n"
+"{\n"
+"  return vec2 (-v.y, v.x);\n"
+"}\n"
+"\n"
+"int\n"
+"glyphy_float_to_byte (const float v)\n"
+"{\n"
+"  return int (v * (256. - GLYPHY_EPSILON));\n"
+"}\n"
+"\n"
+"ivec4\n"
+"glyphy_vec4_to_bytes (const vec4 v)\n"
+"{\n"
+"  return ivec4 (v * (256. - GLYPHY_EPSILON));\n"
+"}\n"
+"\n"
+"ivec2\n"
+"glyphy_float_to_two_nimbles (const float v)\n"
+"{\n"
+"  int f = glyphy_float_to_byte (v);\n"
+"  return ivec2 (f / 16, int(mod (float(f), 16.)));\n"
+"}\n"
+"\n"
+"/* returns tan (2 * atan (d)) */\n"
+"float\n"
+"glyphy_tan2atan (const float d)\n"
+"{\n"
+"  return 2. * d / (1. - d * d);\n"
+"}\n"
+"\n"
+"glyphy_arc_endpoint_t\n"
+"glyphy_arc_endpoint_decode (const vec4 v, const ivec2 nominal_size)\n"
+"{\n"
+"  vec2 p = (vec2 (glyphy_float_to_two_nimbles (v.a)) + v.gb) / 16.;\n"
+"  float d = v.r;\n"
+"  if (d == 0.)\n"
+"    d = GLYPHY_INFINITY;\n"
+"  else\n"
+"#define GLYPHY_MAX_D .5\n"
+"    d = float(glyphy_float_to_byte (d) - 128) * GLYPHY_MAX_D / 127.;\n"
+"#undef GLYPHY_MAX_D\n"
+"  return glyphy_arc_endpoint_t (p * vec2(nominal_size), d);\n"
+"}\n"
+"\n"
+"vec2\n"
+"glyphy_arc_center (const glyphy_arc_t a)\n"
+"{\n"
+"  return mix (a.p0, a.p1, .5) +\n"
+"       glyphy_ortho (a.p1 - a.p0) / (2. * glyphy_tan2atan (a.d));\n"
+"}\n"
+"\n"
+"bool\n"
+"glyphy_arc_wedge_contains (const glyphy_arc_t a, const vec2 p)\n"
+"{\n"
+"  float d2 = glyphy_tan2atan (a.d);\n"
+"  return dot (p - a.p0, (a.p1 - a.p0) * mat2(1,  d2, -d2, 1)) >= 0. &&\n"
+"       dot (p - a.p1, (a.p1 - a.p0) * mat2(1, -d2,  d2, 1)) <= 0.;\n"
+"}\n"
+"\n"
+"float\n"
+"glyphy_arc_wedge_signed_dist_shallow (const glyphy_arc_t a, const vec2 p)\n"
+"{\n"
+"  vec2 v = normalize (a.p1 - a.p0);\n"
+"  float line_d = dot (p - a.p0, glyphy_ortho (v));\n"
+"  if (a.d == 0.)\n"
+"    return line_d;\n"
+"\n"
+"  float d0 = dot ((p - a.p0), v);\n"
+"  if (d0 < 0.)\n"
+"    return sign (line_d) * distance (p, a.p0);\n"
+"  float d1 = dot ((a.p1 - p), v);\n"
+"  if (d1 < 0.)\n"
+"    return sign (line_d) * distance (p, a.p1);\n"
+"  float r = 2. * a.d * (d0 * d1) / (d0 + d1);\n"
+"  if (r * line_d > 0.)\n"
+"    return sign (line_d) * min (abs (line_d + r), min (distance (p, a.p0), distance (p, a.p1)));\n"
+"  return line_d + r;\n"
+"}\n"
+"\n"
+"float\n"
+"glyphy_arc_wedge_signed_dist (const glyphy_arc_t a, const vec2 p)\n"
+"{\n"
+"  if (abs (a.d) <= .03)\n"
+"    return glyphy_arc_wedge_signed_dist_shallow (a, p);\n"
+"  vec2 c = glyphy_arc_center (a);\n"
+"  return sign (a.d) * (distance (a.p0, c) - distance (p, c));\n"
+"}\n"
+"\n"
+"float\n"
+"glyphy_arc_extended_dist (const glyphy_arc_t a, const vec2 p)\n"
+"{\n"
+"  /* Note: this doesn't handle points inside the wedge. */\n"
+"  vec2 m = mix (a.p0, a.p1, .5);\n"
+"  float d2 = glyphy_tan2atan (a.d);\n"
+"  if (dot (p - m, a.p1 - m) < 0.)\n"
+"    return dot (p - a.p0, normalize ((a.p1 - a.p0) * mat2(+d2, -1, +1, +d2)));\n"
+"  else\n"
+"    return dot (p - a.p1, normalize ((a.p1 - a.p0) * mat2(-d2, -1, +1, -d2)));\n"
+"}\n"
+"\n"
+"int\n"
+"glyphy_arc_list_offset (const vec2 p, const ivec2 nominal_size)\n"
+"{\n"
+"  ivec2 cell = ivec2 (clamp (floor (p), vec2 (0.,0.), vec2(nominal_size - 1)));\n"
+"  return cell.y * nominal_size.x + cell.x;\n"
+"}\n"
+"\n"
+"glyphy_arc_list_t\n"
+"glyphy_arc_list_decode (const vec4 v, const ivec2 nominal_size)\n"
+"{\n"
+"  glyphy_arc_list_t l;\n"
+"  ivec4 iv = glyphy_vec4_to_bytes (v);\n"
+"  l.side = 0; /* unsure */\n"
+"  if (iv.r == 0) { /* arc-list encoded */\n"
+"    l.offset = (iv.g * 256) + iv.b;\n"
+"    l.num_endpoints = iv.a;\n"
+"    if (l.num_endpoints == 255) {\n"
+"      l.num_endpoints = 0;\n"
+"      l.side = -1;\n"
+"    } else if (l.num_endpoints == 0)\n"
+"      l.side = +1;\n"
+"  } else { /* single line encoded */\n"
+"    l.num_endpoints = -1;\n"
+/*"    l.line_distance = float(((iv.r - 128) * 256 + iv.g) - 0x4000) / float (0x1FFF)\n"
+"                    * max (float (nominal_size.x), float (nominal_size.y));\n"
+"    l.line_angle = float(-((iv.b * 256 + iv.a) - 0x8000)) / float (0x7FFF) * 3.14159265358979;\n"*/
+/*"    l.line_distance = float(((iv.r - 128) * 256 + iv.g) - 16384) / 8191.0 \n"
+"                    * max (float (nominal_size.x), float (nominal_size.y));\n"
+"    l.line_angle = float(-((iv.b * 256 + iv.a) - 32768)) / 32767. * 3.14159;\n"*/
+
+"    l.line_distance = ( float(iv.r)/32. + 0.01*float(iv.g)/82.0 - 6.) \n"
+"                    * max (float (nominal_size.x), float (nominal_size.y));\n"
+"    l.line_angle = ( -float(iv.b)/40.74 - float( iv.a )*0.0001 )-3.142;\n"
+"  }\n"
+"  return l;\n"
+"}\n"
+;
diff --git a/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-sdf-glsl.h b/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-sdf-glsl.h
new file mode 100644 (file)
index 0000000..5de751f
--- /dev/null
@@ -0,0 +1,152 @@
+static const char *glyphy_sdf_glsl =
+"/*\n"
+" * Copyright 2012 Google, Inc. All Rights Reserved.\n"
+" *\n"
+" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
+" * you may not use this file except in compliance with the License.\n"
+" * You may obtain a copy of the License at\n"
+" *\n"
+" *     http://www.apache.org/licenses/LICENSE-2.0\n"
+" *\n"
+" * Unless required by applicable law or agreed to in writing, software\n"
+" * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
+" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
+" * See the License for the specific language governing permissions and\n"
+" * limitations under the License.\n"
+" *\n"
+" * Google Author(s): Behdad Esfahbod, Maysum Panju\n"
+" */\n"
+"\n"
+"#ifndef GLYPHY_TEXTURE1D_FUNC\n"
+"#define GLYPHY_TEXTURE1D_FUNC glyphy_texture1D_func\n"
+"#endif\n"
+"#ifndef GLYPHY_TEXTURE1D_EXTRA_DECLS\n"
+"#define GLYPHY_TEXTURE1D_EXTRA_DECLS\n"
+"#endif\n"
+"#ifndef GLYPHY_TEXTURE1D_EXTRA_ARGS\n"
+"#define GLYPHY_TEXTURE1D_EXTRA_ARGS\n"
+"#endif\n"
+"\n"
+"#ifndef GLYPHY_SDF_TEXTURE1D_FUNC\n"
+"#define GLYPHY_SDF_TEXTURE1D_FUNC GLYPHY_TEXTURE1D_FUNC\n"
+"#endif\n"
+"#ifndef GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS\n"
+"#define GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS GLYPHY_TEXTURE1D_EXTRA_DECLS\n"
+"#endif\n"
+"#ifndef GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS\n"
+"#define GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS GLYPHY_TEXTURE1D_EXTRA_ARGS\n"
+"#endif\n"
+"#ifndef GLYPHY_SDF_TEXTURE1D\n"
+"#define GLYPHY_SDF_TEXTURE1D(offset) GLYPHY_RGBA(GLYPHY_SDF_TEXTURE1D_FUNC (offset GLYPHY_TEXTURE1D_EXTRA_ARGS))\n"
+"#endif\n"
+"\n"
+"#ifndef GLYPHY_MAX_NUM_ENDPOINTS\n"
+"#define GLYPHY_MAX_NUM_ENDPOINTS 32\n"
+"#endif\n"
+"\n"
+"glyphy_arc_list_t\n"
+"glyphy_arc_list (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)\n"
+"{\n"
+"  int cell_offset = glyphy_arc_list_offset (p, nominal_size);\n"
+"  vec4 arc_list_data = GLYPHY_SDF_TEXTURE1D (cell_offset);\n"
+"  return glyphy_arc_list_decode (arc_list_data, nominal_size);\n"
+"}\n"
+"\n"
+"float\n"
+"glyphy_sdf (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)\n"
+"{\n"
+"  glyphy_arc_list_t arc_list = glyphy_arc_list (p, nominal_size  GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS);\n"
+"\n"
+"  /* Short-circuits */\n"
+"  if (arc_list.num_endpoints == 0) {\n"
+"    /* far-away cell */\n"
+"    return GLYPHY_INFINITY * float(arc_list.side);\n"
+"  } if (arc_list.num_endpoints == -1) {\n"
+"    /* single-line */\n"
+"    float angle = arc_list.line_angle;\n"
+"    vec2 n = vec2 (cos (angle), sin (angle));\n"
+"    return dot (p - (vec2(nominal_size) * .5), n) - arc_list.line_distance;\n"
+"  }\n"
+"\n"
+"  float side = float(arc_list.side);\n"
+"  float min_dist = GLYPHY_INFINITY;\n"
+"  glyphy_arc_t closest_arc;\n"
+"\n"
+"  glyphy_arc_endpoint_t endpoint_prev, endpoint;\n"
+"  endpoint_prev = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset), nominal_size);\n"
+"  for (int i = 1; i < GLYPHY_MAX_NUM_ENDPOINTS; i++)\n"
+"  {\n"
+"    if (i >= arc_list.num_endpoints) {\n"
+"      break;\n"
+"    }\n"
+"    endpoint = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset + i), nominal_size);\n"
+"    glyphy_arc_t a = glyphy_arc_t (endpoint_prev.p, endpoint.p, endpoint.d);\n"
+"    endpoint_prev = endpoint;\n"
+"    if (glyphy_isinf (a.d)) continue;\n"
+"\n"
+"    if (glyphy_arc_wedge_contains (a, p))\n"
+"    {\n"
+"      float sdist = glyphy_arc_wedge_signed_dist (a, p);\n"
+"      float udist = abs (sdist) * (1. - GLYPHY_EPSILON);\n"
+"      if (udist <= min_dist) {\n"
+"       min_dist = udist;\n"
+"       side = sign (sdist);"
+"      }\n"
+"    } else {\n"
+"      float udist = min (distance (p, a.p0), distance (p, a.p1));\n"
+"      if (udist < min_dist) {\n"
+"       min_dist = udist;\n"
+"       side = 0.; /* unsure */\n"
+"       closest_arc = a;\n"
+"      } else if (side == 0. && udist == min_dist) {\n"
+"       /* If this new distance is the same as the current minimum,\n"
+"        * compare extended distances.  Take the sign from the arc\n"
+"        * with larger extended distance. */\n"
+"       float old_ext_dist = glyphy_arc_extended_dist (closest_arc, p);\n"
+"       float new_ext_dist = glyphy_arc_extended_dist (a, p);\n"
+"\n"
+"       float ext_dist = abs (new_ext_dist) <= abs (old_ext_dist) ?\n"
+"                        old_ext_dist : new_ext_dist;\n"
+"\n"
+"#ifdef GLYPHY_SDF_PSEUDO_DISTANCE\n"
+"       /* For emboldening and stuff: */\n"
+"       min_dist = abs (ext_dist);\n"
+"#endif\n"
+"       side = sign (ext_dist);\n"
+"      }\n"
+"    }\n"
+"  }\n"
+"\n"
+"  if (side == 0.) {\n"
+"    // Technically speaking this should not happen, but it does.  So try to fix it.\n"
+"    float ext_dist = glyphy_arc_extended_dist (closest_arc, p);\n"
+"    side = sign (ext_dist);\n"
+"  }\n"
+"\n"
+"  return min_dist * side;\n"
+"}\n"
+"\n"
+"float\n"
+"glyphy_point_dist (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)\n"
+"{\n"
+"  glyphy_arc_list_t arc_list = glyphy_arc_list (p, nominal_size  GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS);\n"
+"\n"
+"  float side = float(arc_list.side);\n"
+"  float min_dist = GLYPHY_INFINITY;\n"
+"\n"
+"  if (arc_list.num_endpoints == 0)\n"
+"    return min_dist;\n"
+"\n"
+"  glyphy_arc_endpoint_t endpoint;\n"
+"  for (int i = 0; i < GLYPHY_MAX_NUM_ENDPOINTS; i++)\n"
+"  {\n"
+"    if (i >= arc_list.num_endpoints) {\n"
+"      break;\n"
+"    }\n"
+"    endpoint = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset + i), nominal_size);\n"
+"    if (glyphy_isinf (endpoint.d)) continue;\n"
+"    min_dist = min (min_dist, distance (p, endpoint.p));\n"
+"  }\n"
+"  return min_dist;\n"
+"}\n"
+;
diff --git a/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.cpp b/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.cpp
new file mode 100644 (file)
index 0000000..53db8fb
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * 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-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h>
+
+// EXTERNAL HEADERS
+#include <sstream>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-common-glsl.h>
+#include <dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-sdf-glsl.h>
+
+using namespace Dali;
+
+namespace
+{
+
+const char* const ENABLE_EXTENSION_PREFIX =
+"#extension GL_OES_standard_derivatives : enable\n"
+"precision highp float;\n"
+"precision highp int;\n";
+
+const char* const VERTEX_SHADER_MAIN =
+"uniform   mediump mat4    uProjection;\n"
+"uniform   mediump mat4    uModelView;\n"
+"uniform   mediump mat4    uMvpMatrix;\n"
+"uniform           bool    uTextureMapped;\n"
+"uniform   mediump vec4    uCustomTextureCoords;\n"
+"attribute highp   vec2    aTexCoord;\n"
+"varying   mediump vec2    vTexCoord;\n"
+"uniform   mat3            uModelViewIT;\n"
+"attribute mediump vec3    aNormal;\n"
+"varying   mediump vec3    vNormal;\n"
+"attribute mediump vec2    aPosition;\n"
+"varying   mediump vec4    vVertex;\n"
+"varying vec4 v_glyph;\n"
+"\n"
+"vec4\n"
+"glyph_vertex_transcode (vec2 v)\n"
+"{\n"
+"  ivec2 g = ivec2 (v);\n"
+"  ivec2 corner = ivec2 (mod (v, 2.));\n"
+"  g /= 2;\n"
+"  ivec2 nominal_size = ivec2 (mod (vec2(g), 64.));\n"
+"  return vec4 (corner * nominal_size, g * 4);\n"
+"}\n"
+"\n"
+"void\n"
+"main()\n"
+"{\n"
+"  gl_Position = uMvpMatrix * vec4 (aPosition, 0.0, 1.0);\n"
+"  v_glyph = glyph_vertex_transcode (aTexCoord);\n"
+"}\n"
+;
+
+const char* const FRAGMENT_SHADER_PREFIX =
+"struct Material\n"
+"{\n"
+"  mediump float mOpacity;\n"
+"  mediump float mShininess;\n"
+"  lowp    vec4  mAmbient;\n"
+"  lowp    vec4  mDiffuse;\n"
+"  lowp    vec4  mSpecular;\n"
+"  lowp    vec4  mEmissive;\n"
+"};\n"
+"uniform sampler2D     sTexture;\n"
+"uniform sampler2D     sOpacityTexture;\n"
+"uniform sampler2D     sNormalMapTexture;\n"
+"uniform sampler2D     sEffect;\n"
+"varying mediump vec2 vTexCoord;\n"
+"uniform Material      uMaterial;\n"
+"uniform lowp  vec4    uColor;\n"
+"varying highp vec4    vVertex;\n"
+"varying highp vec3    vNormal;\n"
+"uniform vec4 u_atlas_info;\n"
+"\n"
+"#define GLYPHY_TEXTURE1D_EXTRA_DECLS , sampler2D _tex, ivec4 _atlas_info, ivec2 _atlas_pos\n"
+"#define GLYPHY_TEXTURE1D_EXTRA_ARGS , _tex, _atlas_info, _atlas_pos\n"
+"#define GLYPHY_DEMO_EXTRA_ARGS , sTexture, uu_atlas_info, gi.atlas_pos\n"
+"\n"
+"vec4\n"
+"glyphy_texture1D_func (int offset GLYPHY_TEXTURE1D_EXTRA_DECLS)\n"
+"{\n"
+"  ivec2 item_geom = _atlas_info.zw;\n"
+"  vec2 pos = (vec2 (_atlas_pos.xy * item_geom +\n"
+"                    ivec2 (mod (float (offset), float (item_geom.x)), offset / item_geom.x)) +\n"
+"             + vec2 (.5, .5)) / vec2(_atlas_info.xy);\n"
+"  return texture2D (_tex, pos);\n"
+"}\n"
+;
+
+static const char* FRAGMENT_SHADER_MAIN =
+"uniform float u_contrast;\n"
+"uniform float u_gamma_adjust;\n"
+"uniform float u_outline_thickness;\n"
+"uniform float u_outline;\n"
+"uniform float u_boldness;\n"
+"\n"
+"varying vec4 v_glyph;\n"
+"\n"
+"\n"
+"#define SQRT2_2 0.70711 /* 1 / sqrt(2.) */\n"
+"#define SQRT2   1.41421\n"
+"\n"
+"struct glyph_info_t {\n"
+"  ivec2 nominal_size;\n"
+"  ivec2 atlas_pos;\n"
+"};\n"
+"\n"
+"glyph_info_t\n"
+"glyph_info_decode (vec4 v)\n"
+"{\n"
+"  glyph_info_t gi;\n"
+"  gi.nominal_size = (ivec2 (mod (v.zw, 256.)) + 2) / 4;\n"
+"  gi.atlas_pos = ivec2 (v_glyph.zw) / 256;\n"
+"  return gi;\n"
+"}\n"
+"\n"
+"\n"
+"float\n"
+"antialias (float d)\n"
+"{\n"
+"  return smoothstep (-.75, +.75, d);\n"
+"}\n"
+"\n"
+"vec4\n"
+"source_over (const vec4 src, const vec4 dst)\n"
+"{\n"
+"  // http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators_srcover\n"
+"  float alpha = src.a + (dst.a * (1. - src.a));\n"
+"  return vec4 (((src.rgb * src.a) + (dst.rgb * dst.a * (1. - src.a))) / alpha, alpha);\n"
+"}\n"
+"\n"
+"void\n"
+"main()\n"
+"{\n"
+"  vec2 p = v_glyph.xy;\n"
+"  glyph_info_t gi = glyph_info_decode (v_glyph);\n"
+"\n"
+"  /* isotropic antialiasing */\n"
+"  vec2 dpdx = dFdx (p);\n"
+"  vec2 dpdy = dFdy (p);\n"
+"  float m = length (vec2 (length (dpdx), length (dpdy))) * SQRT2_2;\n"
+"\n"
+"  vec4 color = uColor;\n"
+"\n"
+"  ivec4 uu_atlas_info = ivec4( u_atlas_info );"
+"  float gsdist = glyphy_sdf (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n"
+"  float sdist = gsdist / m * u_contrast;\n"
+"\n"
+"    sdist -= u_boldness * 10.;\n"
+"    if ( glyphy_iszero( u_outline ) )\n"
+"      sdist = abs (sdist) - u_outline_thickness * .5;\n"
+"    if (sdist > 1.)\n"
+"      discard;\n"
+"    float alpha = antialias (-sdist);\n"
+"    if (u_gamma_adjust != 1.)\n"
+"      alpha = pow (alpha, 1./u_gamma_adjust);\n"
+"    color = vec4 (color.rgb,color.a * alpha);\n"
+"\n"
+"  gl_FragColor = color;\n"
+"}\n"
+;
+
+} // namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+GlyphyShader::GlyphyShader()
+{
+}
+
+GlyphyShader::GlyphyShader( Shader handle )
+: Shader( handle )
+{
+}
+
+GlyphyShader::~GlyphyShader()
+{
+}
+
+GlyphyShader GlyphyShader::New( const Dali::Vector4& atlasInfo )
+{
+  std::ostringstream vertexShaderStringStream;
+  std::ostringstream fragmentShaderStringStream;
+
+  vertexShaderStringStream << ENABLE_EXTENSION_PREFIX << VERTEX_SHADER_MAIN;
+
+  fragmentShaderStringStream << ENABLE_EXTENSION_PREFIX
+                             << FRAGMENT_SHADER_PREFIX
+                             << glyphy_common_glsl
+                             << "#define GLYPHY_SDF_PSEUDO_DISTANCE 1\n"
+                             << glyphy_sdf_glsl
+                             << FRAGMENT_SHADER_MAIN;
+
+  Shader shaderEffectCustom = Shader::New( vertexShaderStringStream.str(),
+                                           fragmentShaderStringStream.str(),
+                                           Shader::ShaderHints( Shader::HINT_OUTPUT_IS_TRANSPARENT ) );
+
+  GlyphyShader handle( shaderEffectCustom );
+
+  handle.RegisterProperty( "u_atlas_info",  atlasInfo );
+  handle.RegisterProperty( "u_contrast",          1.f );
+  handle.RegisterProperty( "u_gamma_adjust",      1.f );
+  handle.RegisterProperty( "u_outline_thickness", 1.f );
+  handle.RegisterProperty( "u_outline",           1.f );
+  handle.RegisterProperty( "u_boldness",          0.f );
+
+  return handle;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h b/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h
new file mode 100644 (file)
index 0000000..b3bbcf7
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef __DALI_TOOLKIT_TEXT_GLYPHY_SHADER_H__
+#define __DALI_TOOLKIT_TEXT_GLYPHY_SHADER_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.
+ *
+ */
+
+// INTERNEL INCLUDES
+#include <dali/public-api/math/vector4.h>
+#include <dali/devel-api/rendering/shader.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief A Shader based on GLyphy authored by Behdad Esfahbod & Maysum Panju.
+ *
+ * See https://github.com/behdad/glyphy for more details of GLyphy.
+ */
+class GlyphyShader : public Shader
+{
+public:
+
+  /**
+   * @brief Create the blob atlas.
+   *
+   * @param[in] atlasInfo The metrics of the texture atlas storing vector data.
+   */
+  static GlyphyShader New( const Vector4& atlasInfo );
+
+  /**
+   * @brief Create an uninitialized GlyphyShader handle.
+   */
+  GlyphyShader();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~GlyphyShader();
+
+private: // Not intended for application developer
+
+  GlyphyShader( Shader handle );
+
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_GLYPHY_SHADER_H__
diff --git a/dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.cpp b/dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.cpp
new file mode 100644 (file)
index 0000000..816a45d
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * 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-toolkit/internal/text/rendering/vector-based/vector-based-renderer.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/rendering/renderer.h>
+#include <dali/devel-api/rendering/geometry.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/glyph-run.h>
+#include <dali-toolkit/internal/text/text-view.h>
+#include <dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h>
+#include <dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h>
+#include <dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+using namespace Dali::Toolkit::Text;
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
+#endif
+
+const float DEFAULT_POINT_SIZE = 13.f;
+
+struct Vertex2D
+{
+  float x;
+  float y;
+  float u;
+  float v;
+};
+
+void AddVertex( Vector<Vertex2D>& vertices, float x, float y, float u, float v )
+{
+  Vertex2D meshVertex;
+  meshVertex.x = x;
+  meshVertex.y = y;
+  meshVertex.u = u;
+  meshVertex.v = v;
+  vertices.PushBack( meshVertex );
+}
+
+void AddTriangle( Vector<unsigned int>& indices, unsigned int v0, unsigned int v1, unsigned int v2 )
+{
+  indices.PushBack( v0 );
+  indices.PushBack( v1 );
+  indices.PushBack( v2 );
+}
+
+bool CreateGeometry( const Vector<GlyphInfo>& glyphs,
+                     unsigned int numberOfGlyphs,
+                     const Vector<Vector2>& positions,
+                     float xOffset,
+                     float yOffset,
+                     VectorBlobAtlas& atlas,
+                     Dali::TextAbstraction::FontClient& fontClient,
+                     Vector< Vertex2D >& vertices,
+                     Vector< unsigned int >& indices )
+{
+  bool atlasFull( false );
+
+  for( unsigned int i=0, idx=0; i<numberOfGlyphs && !atlasFull; ++i )
+  {
+    if( glyphs[i].width  > 0 &&
+        glyphs[i].height > 0 )
+    {
+      bool foundBlob( true );
+
+      BlobCoordinate blobCoords[4];
+
+      if( ! atlas.FindGlyph( glyphs[i].fontId, glyphs[i].index, blobCoords )  )
+      {
+        // Add blob to atlas
+        VectorBlob* blob( NULL );
+        unsigned int blobLength( 0 );
+        unsigned int nominalWidth( 0 );
+        unsigned int nominalHeight( 0 );
+        fontClient.CreateVectorBlob( glyphs[i].fontId, glyphs[i].index, blob, blobLength, nominalWidth, nominalHeight );
+
+        if( 0 != blobLength )
+        {
+          bool glyphAdded = atlas.AddGlyph( glyphs[i].fontId, glyphs[i].index, blob, blobLength, nominalWidth, nominalHeight, blobCoords );
+
+          foundBlob = glyphAdded;
+          atlasFull = !glyphAdded;
+        }
+        else
+        {
+          foundBlob = false;
+        }
+      }
+
+      if( foundBlob )
+      {
+        const float x1( xOffset + positions[i].x );
+        const float x2( xOffset + positions[i].x + glyphs[i].width );
+        const float y1( yOffset + positions[i].y );
+        const float y2( yOffset + positions[i].y + glyphs[i].height );
+
+        AddVertex( vertices, x1, y2, blobCoords[0].u, blobCoords[0].v );
+        AddVertex( vertices, x1, y1, blobCoords[1].u, blobCoords[1].v );
+        AddVertex( vertices, x2, y2, blobCoords[2].u, blobCoords[2].v );
+        AddTriangle( indices, idx, idx+1, idx+2 );
+        idx+=3;
+
+        AddVertex( vertices, x1, y1, blobCoords[1].u, blobCoords[1].v );
+        AddVertex( vertices, x2, y2, blobCoords[2].u, blobCoords[2].v );
+        AddVertex( vertices, x2, y1, blobCoords[3].u, blobCoords[3].v );
+        AddTriangle( indices, idx, idx+1, idx+2 );
+        idx+=3;
+      }
+    }
+  }
+
+  // If the atlas is still partially empty, all the glyphs were added
+  return !atlasFull;
+}
+
+} // unnamed namespace
+
+struct VectorBasedRenderer::Impl
+{
+  Impl()
+  {
+    mFontClient = TextAbstraction::FontClient::Get();
+
+    mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
+    mQuadVertexFormat[ "aTexCoord" ] = Property::VECTOR2;
+    mQuadIndexFormat[ "indices" ] = Property::INTEGER;
+  }
+
+  Actor mActor;                            ///< The actor parent which renders the text
+
+  TextAbstraction::FontClient mFontClient; ///> The font client used to supply glyph information
+
+  Property::Map mQuadVertexFormat;         ///> Describes the vertex format for text
+  Property::Map mQuadIndexFormat;          ///> Describes the index format for text
+
+  Shader mShaderEffect;
+
+  IntrusivePtr<VectorBlobAtlas> mAtlas;
+};
+
+Text::RendererPtr VectorBasedRenderer::New()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::VectorBasedRenderer::New()\n" );
+
+  return Text::RendererPtr( new VectorBasedRenderer() );
+}
+
+Actor VectorBasedRenderer::Render( Text::ViewInterface& view, int /*depth*/ )
+{
+  UnparentAndReset( mImpl->mActor );
+
+  mImpl->mActor = Actor::New();
+  mImpl->mActor.SetParentOrigin( ParentOrigin::CENTER );
+  mImpl->mActor.SetSize( view.GetControlSize() );
+  mImpl->mActor.SetColor( Color::BLACK );
+#if defined(DEBUG_ENABLED)
+  mImpl->mActor.SetName( "Text renderable actor" );
+#endif
+
+  Length numberOfGlyphs = view.GetNumberOfGlyphs();
+
+  if( numberOfGlyphs > 0u )
+  {
+    Vector<GlyphInfo> glyphs;
+    glyphs.Resize( numberOfGlyphs );
+
+    Vector<Vector2> positions;
+    positions.Resize( numberOfGlyphs );
+
+    Vector<Vector4> colors;
+    colors.Resize( numberOfGlyphs, view.GetTextColor() );
+
+    numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
+                                     positions.Begin(),
+                                     colors.Begin(),
+                                     0u,
+                                     numberOfGlyphs );
+    glyphs.Resize( numberOfGlyphs );
+    positions.Resize( numberOfGlyphs );
+
+    Vector< Vertex2D > vertices;
+    Vector< unsigned int > indices;
+
+    const Vector2& controlSize = view.GetControlSize();
+    float xOffset = controlSize.width  * -0.5f;
+    float yOffset = controlSize.height * -0.5f;
+
+    if( ! mImpl->mAtlas ||
+          mImpl->mAtlas->IsFull() )
+    {
+      VectorBlobAtlasShare atlasShare = VectorBlobAtlasShare::Get();
+      mImpl->mAtlas = atlasShare.GetCurrentAtlas();
+    }
+
+    // First try adding the glyphs to the previous shared atlas
+    bool allGlyphsAdded = CreateGeometry( glyphs, numberOfGlyphs, positions, xOffset, yOffset, *mImpl->mAtlas, mImpl->mFontClient, vertices, indices );
+
+    if( ! allGlyphsAdded )
+    {
+      // The current atlas is full, abandon it and use a new one
+      mImpl->mAtlas.Reset();
+      vertices.Clear();
+      indices.Clear();
+
+      VectorBlobAtlasShare atlasShare = VectorBlobAtlasShare::Get();
+      mImpl->mAtlas = atlasShare.GetNewAtlas();
+
+      CreateGeometry( glyphs, numberOfGlyphs, positions, xOffset, yOffset, *mImpl->mAtlas, mImpl->mFontClient, vertices, indices );
+      // Return value ignored; using more than an entire new atlas is not supported
+    }
+
+    if( 0 != vertices.Count() )
+    {
+      PropertyBuffer quadVertices = PropertyBuffer::New( mImpl->mQuadVertexFormat );
+      PropertyBuffer quadIndices = PropertyBuffer::New( mImpl->mQuadIndexFormat );
+
+      quadVertices.SetData( &vertices[ 0 ], vertices.Size() );
+      quadIndices.SetData( &indices[ 0 ], indices.Size() );
+
+      Geometry quadGeometry = Geometry::New();
+      quadGeometry.AddVertexBuffer( quadVertices );
+      quadGeometry.SetIndexBuffer( quadIndices );
+
+      TextureSet texture = mImpl->mAtlas->GetTextureSet();
+
+      const Vector4 atlasInfo = mImpl->mAtlas->GetInfo();
+      mImpl->mShaderEffect = GlyphyShader::New( atlasInfo );
+
+      Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, mImpl->mShaderEffect );
+      renderer.SetTextures( texture );
+      mImpl->mActor.AddRenderer( renderer );
+    }
+  }
+
+  return mImpl->mActor;
+}
+
+VectorBasedRenderer::VectorBasedRenderer()
+{
+  mImpl = new Impl();
+}
+
+VectorBasedRenderer::~VectorBasedRenderer()
+{
+  delete mImpl;
+}
+
diff --git a/dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.h b/dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.h
new file mode 100644 (file)
index 0000000..0b7a44e
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef __DALI_TOOLKIT_TEXT_VECTOR_BASED_RENDERER_H__
+#define __DALI_TOOLKIT_TEXT_VECTOR_BASED_RENDERER_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/text-renderer.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief A vector-based renderer
+ *
+ */
+class VectorBasedRenderer : public Renderer
+{
+public:
+
+  /**
+   * @brief Create the renderer.
+   */
+  static RendererPtr New();
+
+  /**
+   * @brief Render the glyphs from a ViewInterface.
+   *
+   * @param[in] view The interface to a view.
+   * @param[in] depth The depth in the tree of the parent.
+   * @return The Renderable actor used to position the text.
+   */
+  virtual Actor Render( ViewInterface& view, int depth );
+
+protected:
+
+  /**
+   * @brief Constructor.
+   */
+  VectorBasedRenderer();
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~VectorBasedRenderer();
+
+private:
+
+  // Undefined
+  VectorBasedRenderer( const VectorBasedRenderer& handle );
+
+  // Undefined
+  VectorBasedRenderer& operator=( const VectorBasedRenderer& handle );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_VECTOR_BASED_RENDERER_H__
diff --git a/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.cpp b/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.cpp
new file mode 100644 (file)
index 0000000..81a2817
--- /dev/null
@@ -0,0 +1,150 @@
+ /*
+ * 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-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+#include <dali/devel-api/adaptor-framework/singleton-service.h>
+
+namespace
+{
+
+const int INITIAL_VECTOR_BLOB_ATLAS_WIDTH = 512;
+const int INITIAL_VECTOR_BLOB_ATLAS_HEIGHT = 512;
+
+const int NEW_VECTOR_BLOB_ATLAS_WIDTH = 1024;
+const int NEW_VECTOR_BLOB_ATLAS_HEIGHT = 1024;
+
+const int VECTOR_BLOB_ATLAS_ITEM_WIDTH = 64;
+const int VECTOR_BLOB_ATLAS_HEIGHT_QUANTUM = 8;
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class VectorBlobAtlasShare::Impl : public Dali::BaseObject
+{
+public:
+
+  /**
+   * @brief Constructor
+   */
+  Impl()
+  {
+  }
+
+  VectorBlobAtlas* GetCurrentAtlas()
+  {
+    if( ! mCurrentAtlas )
+    {
+      mCurrentAtlas = new VectorBlobAtlas( INITIAL_VECTOR_BLOB_ATLAS_WIDTH, INITIAL_VECTOR_BLOB_ATLAS_HEIGHT, VECTOR_BLOB_ATLAS_ITEM_WIDTH, VECTOR_BLOB_ATLAS_HEIGHT_QUANTUM );
+    }
+
+    return mCurrentAtlas.Get();
+  }
+
+  VectorBlobAtlas* GetNewAtlas()
+  {
+    // The current atlas should have been filled, before asking for a new one
+    DALI_ASSERT_DEBUG( mCurrentAtlas->IsFull() && "Current atlas is not full yet" );
+
+    mCurrentAtlas = new VectorBlobAtlas( NEW_VECTOR_BLOB_ATLAS_WIDTH, NEW_VECTOR_BLOB_ATLAS_HEIGHT, VECTOR_BLOB_ATLAS_ITEM_WIDTH, VECTOR_BLOB_ATLAS_HEIGHT_QUANTUM );
+
+    return mCurrentAtlas.Get();
+  }
+
+protected:
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Impl()
+  {
+  }
+
+private:
+
+  IntrusivePtr<VectorBlobAtlas> mCurrentAtlas;
+};
+
+VectorBlobAtlasShare::VectorBlobAtlasShare()
+{
+}
+
+VectorBlobAtlasShare::~VectorBlobAtlasShare()
+{
+}
+
+VectorBlobAtlasShare VectorBlobAtlasShare::Get()
+{
+  VectorBlobAtlasShare manager;
+
+  // Check whether the VectorBlobAtlasShare is already created
+  SingletonService singletonService( SingletonService::Get() );
+  if ( singletonService )
+  {
+    Dali::BaseHandle handle = singletonService.GetSingleton( typeid( VectorBlobAtlasShare ) );
+    if( handle )
+    {
+      // If so, downcast the handle of singleton to VectorBlobAtlasShare
+      manager = VectorBlobAtlasShare( dynamic_cast<VectorBlobAtlasShare::Impl*>( handle.GetObjectPtr() ) );
+    }
+
+    if( !manager )
+    {
+      // If not, create the VectorBlobAtlasShare and register it as a singleton
+      manager = VectorBlobAtlasShare( new VectorBlobAtlasShare::Impl() );
+      singletonService.Register( typeid( manager ), manager );
+    }
+  }
+
+  return manager;
+}
+
+VectorBlobAtlasShare::VectorBlobAtlasShare( VectorBlobAtlasShare::Impl* impl )
+: BaseHandle( impl )
+{
+}
+
+VectorBlobAtlas* VectorBlobAtlasShare::GetCurrentAtlas()
+{
+  VectorBlobAtlasShare::Impl& impl = static_cast<VectorBlobAtlasShare::Impl&>( GetBaseObject() );
+
+  return impl.GetCurrentAtlas();
+}
+
+VectorBlobAtlas* VectorBlobAtlasShare::GetNewAtlas()
+{
+  VectorBlobAtlasShare::Impl& impl = static_cast<VectorBlobAtlasShare::Impl&>( GetBaseObject() );
+
+  return impl.GetNewAtlas();
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h b/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h
new file mode 100644 (file)
index 0000000..a854089
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef __DALI_TOOLKIT_VECTOR_BLOB_ATLAS_SHARE_H__
+#define __DALI_TOOLKIT_VECTOR_BLOB_ATLAS_SHARE_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief A singleton for sharing atlases containing vector data
+ *
+ */
+class VectorBlobAtlasShare : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Create a VectorBlobAtlasShare handle.
+   *
+   * Calling member functions with an uninitialised handle is not allowed.
+   */
+  VectorBlobAtlasShare();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~VectorBlobAtlasShare();
+
+  /**
+   * @brief Create or retrieve VectorBlobAtlasShare singleton.
+   *
+   * @return A handle to the VectorBlobAtlasShare control.
+   */
+  static VectorBlobAtlasShare Get();
+
+  /**
+   * @brief Retrieve the current (empty or partially empty) atlas.
+   *
+   * @return The current atlas.
+   */
+  VectorBlobAtlas* GetCurrentAtlas();
+
+  /**
+   * @brief Retrieve a new empty atlas.
+   *
+   * @pre The current atlas should be full.
+   * @return A new atlas.
+   */
+  VectorBlobAtlas* GetNewAtlas();
+
+private:
+
+  class Impl;
+
+  explicit DALI_INTERNAL VectorBlobAtlasShare( VectorBlobAtlasShare::Impl* impl );
+
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_VECTOR_BLOB_ATLAS_SHARE_H__
diff --git a/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.cpp b/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.cpp
new file mode 100644 (file)
index 0000000..360cedf
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * 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-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
+#endif
+
+}
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+static void
+EncodeBlobCoordinate( unsigned int cornerX, unsigned int cornerY,
+                      unsigned int atlasX, unsigned int atlasY,
+                      unsigned int nominalWidth, unsigned int nominalHeight,
+                      BlobCoordinate* v )
+{
+  DALI_ASSERT_DEBUG(0 == (atlasX & ~0x7F));
+  DALI_ASSERT_DEBUG(0 == (atlasY & ~0x7F));
+  DALI_ASSERT_DEBUG(0 == (cornerX & ~1));
+  DALI_ASSERT_DEBUG(0 == (cornerY & ~1));
+  DALI_ASSERT_DEBUG(0 == (nominalWidth & ~0x3F));
+  DALI_ASSERT_DEBUG(0 == (nominalHeight & ~0x3F));
+
+  unsigned int x = (((atlasX << 6) | nominalWidth) << 1)  | cornerX;
+  unsigned int y = (((atlasY << 6) | nominalHeight) << 1) | cornerY;
+
+  unsigned int encoded = (x << 16) | y;
+
+  v->u = encoded >> 16;
+  v->v = encoded & 0xFFFF;
+}
+
+VectorBlobAtlas::VectorBlobAtlas( unsigned int textureWidth,
+                                  unsigned int textureHeight,
+                                  unsigned int itemWidth,
+                                  unsigned int itemHeightQuantum )
+: mTextureWidth( textureWidth ),
+  mTextureHeight( textureHeight ),
+  mItemWidth( itemWidth ),
+  mItemHeightQuantum( itemHeightQuantum ),
+  mCursorX( 0 ),
+  mCursorY( 0 ),
+  mIsFull( false )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Blob atlas %p size %dx%d, item width %d, height quantum %d\n", this, textureWidth, textureHeight, itemWidth, itemHeightQuantum );
+
+  mAtlasTexture = BufferImage::New( textureWidth, textureHeight, Pixel::RGBA8888 );
+
+  mTextureSet = TextureSet::New();
+  mTextureSet.SetImage( 0, mAtlasTexture );
+}
+
+bool VectorBlobAtlas::IsFull() const
+{
+  return mIsFull;
+}
+
+bool VectorBlobAtlas::FindGlyph( FontId fontId,
+                                 GlyphIndex glyphIndex,
+                                 BlobCoordinate* coords )
+{
+  const unsigned int size( mItemLookup.size() );
+
+  for( unsigned int i=0; i<size; ++i )
+  {
+    if( mItemLookup[i].fontId     == fontId &&
+        mItemLookup[i].glyphIndex == glyphIndex )
+    {
+      const Item& item = mItemCache[ mItemLookup[i].cacheIndex ];
+
+      coords[0] = item.coords[0];
+      coords[1] = item.coords[1];
+      coords[2] = item.coords[2];
+      coords[3] = item.coords[3];
+
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool VectorBlobAtlas::AddGlyph( unsigned int fontId,
+                                unsigned int glyphIndex,
+                                VectorBlob* blob,
+                                unsigned int length,
+                                unsigned int nominalWidth,
+                                unsigned int nominalHeight,
+                                BlobCoordinate* coords )
+{
+  if( mIsFull )
+  {
+    return false;
+  }
+
+  unsigned int w, h, x, y;
+
+  w = mItemWidth;
+  h = (length + w - 1) / w;
+
+  if( mCursorY + h > mTextureHeight )
+  {
+    // Go to next column
+    mCursorX += mItemWidth;
+    mCursorY = 0;
+  }
+
+  if( mCursorX + w <= mTextureWidth && mCursorY + h <= mTextureHeight )
+  {
+    x = mCursorX;
+    y = mCursorY;
+    mCursorY += (h + mItemHeightQuantum - 1) & ~(mItemHeightQuantum - 1);
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "Blob atlas %p is now FULL\n", this );
+
+    // The atlas is now considered to be full
+    mIsFull = true;
+    return false;
+  }
+
+  if (w * h == length)
+  {
+    TexSubImage( x, y, w, h, blob );
+  }
+  else
+  {
+    TexSubImage( x, y, w, h-1, blob );
+
+    // Upload the last row separately
+    TexSubImage( x, y + h - 1, length - (w * (h - 1)), 1 , blob + w * (h - 1));
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Blob atlas %p capacity %d filled %d %f\%\n",
+                 this,
+                 mTextureWidth*mTextureHeight,
+                 mCursorY*mItemWidth + mCursorX*mTextureHeight,
+                 100.0f * (float)(mCursorY*mItemWidth + mCursorX*mTextureHeight) / (float)(mTextureWidth*mTextureHeight) );
+
+  Key key;
+  key.fontId = fontId;
+  key.glyphIndex = glyphIndex;
+  key.cacheIndex = mItemCache.size();
+  mItemLookup.push_back( key );
+
+  x /= mItemWidth;
+  y /= mItemHeightQuantum;
+
+  Item item;
+  EncodeBlobCoordinate( 0, 0, x, y, nominalWidth, nominalHeight, &item.coords[0] ); // BOTTOM_LEFT
+  EncodeBlobCoordinate( 0, 1, x, y, nominalWidth, nominalHeight, &item.coords[1] ); // TOP_LEFT
+  EncodeBlobCoordinate( 1, 0, x, y, nominalWidth, nominalHeight, &item.coords[2] ); // BOTTOM_RIGHT
+  EncodeBlobCoordinate( 1, 1, x, y, nominalWidth, nominalHeight, &item.coords[3] ); // TOP_RIGHT
+  mItemCache.push_back( item );
+
+  coords[0] = item.coords[0];
+  coords[1] = item.coords[1];
+  coords[2] = item.coords[2];
+  coords[3] = item.coords[3];
+
+  return true;
+}
+
+void VectorBlobAtlas::TexSubImage( unsigned int offsetX,
+                                   unsigned int offsetY,
+                                   unsigned int width,
+                                   unsigned int height,
+                                   VectorBlob* blob )
+{
+  PixelBuffer* pixbuf = mAtlasTexture.GetBuffer();
+  size_t pos;
+  size_t dataIndex = 0;
+  for( size_t y= offsetY; y< height + offsetY; y++ )
+  {
+    pos = y * mTextureWidth * 4;
+    for( size_t x = offsetX; x < width + offsetX; x++ )
+    {
+      pixbuf[pos+x*4] =  0xFF & blob[dataIndex].r;
+      pixbuf[pos+x*4+1] = 0xFF & blob[dataIndex].g;
+      pixbuf[pos+x*4+2] = 0xFF & blob[dataIndex].b;
+      pixbuf[pos+x*4+3] = 0xFF & blob[dataIndex].a;
+      dataIndex++;
+    }
+  }
+
+  mAtlasTexture.Update();
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h b/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h
new file mode 100644 (file)
index 0000000..13b226d
--- /dev/null
@@ -0,0 +1,185 @@
+#ifndef __DALI_TOOLKIT_TEXT_VECTOR_BLOB_ATLAS_H__
+#define __DALI_TOOLKIT_TEXT_VECTOR_BLOB_ATLAS_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 <dali/public-api/object/ref-object.h>
+#include <dali/public-api/images/buffer-image.h>
+#include <dali/devel-api/rendering/texture-set.h>
+#include <dali/devel-api/rendering/shader.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+typedef Dali::TextAbstraction::VectorBlob VectorBlob;
+
+struct BlobCoordinate
+{
+  float u;
+  float v;
+};
+
+/**
+ * @brief An atlas for vector blob data
+ *
+ */
+class VectorBlobAtlas : public RefObject
+{
+public:
+
+  /**
+   * @brief Create a blob atlas.
+   *
+   * @param[in] textureWidth The atlas width.
+   * @param[in] textureHeight The atlas height.
+   * @param[in] itemWidth The width of an item in the atlas.
+   * @param[in] itemHeightQuantum The item height quantum.
+   * When blobs are added to columns in the atlas, the Y position is advanced by a multiple of this value.
+   */
+  VectorBlobAtlas( unsigned int textureWidth,
+                   unsigned int textureHeight,
+                   unsigned int itemWidth,
+                   unsigned int itemHeightQuantum );
+
+  /**
+   * @brief Query whether the atlas is full.
+   *
+   * @return True if the atlas is full.
+   */
+  bool IsFull() const;
+
+  /**
+   * @brief Find the UV coordinates for a glyph in the atlas.
+   *
+   * @param[in] fontId The ID of the font containing the glyph.
+   * @param[in] glyphIndex The index of the glyph within the font.
+   * @param[out] coords If the glyph was found, an array of 4 UV coordinates will be returned.
+   * Otherwise coords will not be written into.
+   * @return True if the glyph was found.
+   */
+  bool FindGlyph( FontId fontId,
+                  GlyphIndex glyphIndex,
+                  BlobCoordinate* coords );
+
+  /**
+   * @brief Add a glyph to the atlas.
+   *
+   * @param[in] fontId The ID of the font containing the glyph.
+   * @param[in] glyphIndex The index of the glyph within the font.
+   * @param[in] blobData A blob of vector data representing the glyph.
+   * @param[in] length The length of the blob data.
+   * @param[in] nominalWidth The width of the blob.
+   * @param[in] nominalHeight The height of the blob.
+   * @param[out] coords An array of 4 UV coordinates will be returned.
+   * @return True if the glyph was added. Otherwise the atlas is now full.
+   */
+  bool AddGlyph( unsigned int fontId,
+                 unsigned int glyphIndex,
+                 VectorBlob* blob,
+                 unsigned int length,
+                 unsigned int nominalWidth,
+                 unsigned int nominalHeight,
+                 BlobCoordinate* coords );
+
+  /**
+   * @brief Get the info required by the GLyphy shader.
+   *
+   * @return The shader uniform value.
+   */
+  Vector4 GetInfo() const
+  {
+    return Vector4( mTextureWidth, mTextureHeight, mItemWidth, mItemHeightQuantum );
+  }
+
+  /**
+   * @brief Retrieve the atlas texture.
+   *
+   * @return The texture used for rendering.
+   */
+  TextureSet GetTextureSet()
+  {
+    return mTextureSet;
+  }
+
+private:
+
+  /**
+   * @brief Helper for uploading data to the texture atlas.
+   *
+   * @param[in] offsetX The x position within the atlas.
+   * @param[in] offsetY The y position within the atlas.
+   * @param[in] width The width of the data to upload.
+   * @param[in] height The height of the data to upload.
+   * @param[in] blob The blob of data to upload.
+   */
+  void TexSubImage( unsigned int offsetX,
+                    unsigned int offsetY,
+                    unsigned int width,
+                    unsigned int height,
+                    VectorBlob* blob );
+
+private:
+
+  unsigned int mTextureWidth;
+  unsigned int mTextureHeight;
+
+  unsigned int mItemWidth;
+  unsigned int mItemHeightQuantum;
+
+  unsigned int mCursorX;
+  unsigned int mCursorY;
+
+  BufferImage mAtlasTexture;
+
+  TextureSet mTextureSet;
+
+  struct Key
+  {
+    unsigned int fontId;
+    unsigned int glyphIndex;
+    unsigned int cacheIndex;
+  };
+
+  struct Item
+  {
+    BlobCoordinate coords[4];
+  };
+
+  std::vector< Key >  mItemLookup;
+  std::vector< Item > mItemCache;
+
+  bool mIsFull;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif //  __DALI_TOOLKIT_TEXT_VECTOR_BLOB_ATLAS_H__
index ab41790..f477c15 100644 (file)
@@ -107,6 +107,20 @@ void Controller::EnableTextInput( DecoratorPtr decorator )
   }
 }
 
   }
 }
 
+void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
+{
+  // Metrics for bitmap & vector based glyphs are different
+  mImpl->mMetrics->SetGlyphType( glyphType );
+
+  // Clear the font-specific data
+  ClearFontData();
+
+  mImpl->mOperationsPending = ALL_OPERATIONS;
+  mImpl->mRecalculateNaturalSize = true;
+
+  mImpl->RequestRelayout();
+}
+
 void Controller::SetMarkupProcessorEnabled( bool enable )
 {
   mImpl->mMarkupProcessorEnabled = enable;
 void Controller::SetMarkupProcessorEnabled( bool enable )
 {
   mImpl->mMarkupProcessorEnabled = enable;
@@ -2556,7 +2570,10 @@ void Controller::ClearModelData()
 
 void Controller::ClearFontData()
 {
 
 void Controller::ClearFontData()
 {
-  mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
+  if( mImpl->mFontDefaults )
+  {
+    mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
+  }
   mImpl->mLogicalModel->mFontRuns.Clear();
   mImpl->mVisualModel->mGlyphs.Clear();
   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
   mImpl->mLogicalModel->mFontRuns.Clear();
   mImpl->mVisualModel->mGlyphs.Clear();
   mImpl->mVisualModel->mGlyphsToCharacters.Clear();
index 7e22134..44a0257 100644 (file)
@@ -115,6 +115,13 @@ public:
   void EnableTextInput( DecoratorPtr decorator );
 
   /**
   void EnableTextInput( DecoratorPtr decorator );
 
   /**
+   * @brief Used to switch between bitmap & vector based glyphs
+   *
+   * @param[in] glyphType The type of glyph; note that metrics for bitmap & vector based glyphs are different.
+   */
+  void SetGlyphType( TextAbstraction::GlyphType glyphType );
+
+  /**
    * @brief Enables/disables the mark-up processor.
    *
    * By default is disabled.
    * @brief Enables/disables the mark-up processor.
    *
    * By default is disabled.
index 5640a83..97abfb8 100644 (file)
@@ -30,7 +30,8 @@ namespace Text
 // The type of text renderer required
 enum RenderingType
 {
 // The type of text renderer required
 enum RenderingType
 {
-  RENDERING_SHARED_ATLAS ///< A bitmap-based solution where renderers can share a texture atlas @SINCE_1_0.0
+  RENDERING_SHARED_ATLAS, ///< A bitmap-based solution where renderers can share a texture atlas @SINCE_1_0.0
+  RENDERING_VECTOR_BASED  ///< A solution where glyphs are stored as vectors (scalable). Requires highp shader support. @SINCE_1_1.31
 };
 
 const unsigned int DEFAULT_RENDERING_BACKEND = RENDERING_SHARED_ATLAS;
 };
 
 const unsigned int DEFAULT_RENDERING_BACKEND = RENDERING_SHARED_ATLAS;