From 0302e2897031cbf4ab7f15a93eb784ab85d4507d Mon Sep 17 00:00:00 2001 From: Paul Wisbey Date: Mon, 30 Nov 2015 13:48:04 +0000 Subject: [PATCH] Vector-based text rendering Change-Id: Ieadbb0e545219f8184fe50bb6f00bfaced902184 --- .../src/dali-toolkit/utc-Dali-TextLabel.cpp | 41 ++++ build/tizen/configure.ac | 3 + build/tizen/dali-toolkit/Makefile.am | 8 + .../controls/text-controls/text-field-impl.cpp | 18 +- .../controls/text-controls/text-label-impl.cpp | 20 +- dali-toolkit/internal/text/metrics.h | 15 +- .../internal/text/rendering/text-backend-impl.cpp | 13 + .../internal/text/rendering/vector-based/file.list | 7 + .../glyphy-shader/glyphy-common-glsl.h | 231 +++++++++++++++++ .../vector-based/glyphy-shader/glyphy-sdf-glsl.h | 152 ++++++++++++ .../vector-based/glyphy-shader/glyphy-shader.cpp | 238 ++++++++++++++++++ .../vector-based/glyphy-shader/glyphy-shader.h | 74 ++++++ .../vector-based/vector-based-renderer.cpp | 272 +++++++++++++++++++++ .../rendering/vector-based/vector-based-renderer.h | 87 +++++++ .../vector-based/vector-blob-atlas-share.cpp | 150 ++++++++++++ .../vector-based/vector-blob-atlas-share.h | 91 +++++++ .../rendering/vector-based/vector-blob-atlas.cpp | 225 +++++++++++++++++ .../rendering/vector-based/vector-blob-atlas.h | 185 ++++++++++++++ dali-toolkit/internal/text/text-controller.cpp | 19 +- dali-toolkit/internal/text/text-controller.h | 7 + dali-toolkit/public-api/text/rendering-backend.h | 3 +- 21 files changed, 1852 insertions(+), 7 deletions(-) create mode 100644 dali-toolkit/internal/text/rendering/vector-based/file.list create mode 100644 dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-common-glsl.h create mode 100644 dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-sdf-glsl.h create mode 100644 dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.cpp create mode 100644 dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h create mode 100644 dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.cpp create mode 100644 dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.h create mode 100644 dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.cpp create mode 100644 dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h create mode 100644 dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.cpp create mode 100644 dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp index 5e77ebb..9378648 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp @@ -280,3 +280,44 @@ int UtcDaliToolkitTextLabelLanguagesP(void) 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; +} + diff --git a/build/tizen/configure.ac b/build/tizen/configure.ac index 1fa0845..a861a17 100644 --- a/build/tizen/configure.ac +++ b/build/tizen/configure.ac @@ -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]) +# 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) diff --git a/build/tizen/dali-toolkit/Makefile.am b/build/tizen/dali-toolkit/Makefile.am index a760d27..f803a93 100644 --- a/build/tizen/dali-toolkit/Makefile.am +++ b/build/tizen/dali-toolkit/Makefile.am @@ -32,6 +32,14 @@ include ../../../dali-toolkit/internal/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} diff --git a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp index 981b228..082e7e5 100644 --- a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp @@ -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 ); +#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(); - 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; } @@ -972,6 +984,10 @@ void TextField::OnInitialize() 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 ); diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp index 7ad0bfb..9d3fd45 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -125,13 +125,25 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr { 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(); - 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; } @@ -455,6 +467,10 @@ void TextLabel::OnInitialize() 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 ); diff --git a/dali-toolkit/internal/text/metrics.h b/dali-toolkit/internal/text/metrics.h index 147ae79..5e58f38 100644 --- a/dali-toolkit/internal/text/metrics.h +++ b/dali-toolkit/internal/text/metrics.h @@ -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. @@ -91,7 +101,7 @@ public: */ 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: @@ -108,6 +118,7 @@ private: */ Metrics( TextAbstraction::FontClient& fontClient ) : mFontClient( fontClient ), + mGlyphType( TextAbstraction::BITMAP_GLYPH ), mEmojiSize( 0 ) { } @@ -121,7 +132,7 @@ private: private: TextAbstraction::FontClient mFontClient; - + TextAbstraction::GlyphType mGlyphType; int mEmojiSize; }; diff --git a/dali-toolkit/internal/text/rendering/text-backend-impl.cpp b/dali-toolkit/internal/text/rendering/text-backend-impl.cpp index 776d408..10602c7 100644 --- a/dali-toolkit/internal/text/rendering/text-backend-impl.cpp +++ b/dali-toolkit/internal/text/rendering/text-backend-impl.cpp @@ -25,6 +25,9 @@ // INTERNAL INCLUDES #include #include +#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING +#include +#endif namespace Dali { @@ -91,6 +94,16 @@ RendererPtr Backend::NewRenderer( unsigned int renderingType ) } 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 ); 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 index 0000000..0772a37 --- /dev/null +++ b/dali-toolkit/internal/text/rendering/vector-based/file.list @@ -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 index 0000000..a3a1a30 --- /dev/null +++ b/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-common-glsl.h @@ -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 index 0000000..5de751f --- /dev/null +++ b/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-sdf-glsl.h @@ -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 index 0000000..53db8fb --- /dev/null +++ b/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.cpp @@ -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 + +// EXTERNAL HEADERS +#include + +// INTERNAL INCLUDES +#include +#include + +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 index 0000000..b3bbcf7 --- /dev/null +++ b/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h @@ -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 +#include + +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 index 0000000..816a45d --- /dev/null +++ b/dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.cpp @@ -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 + +// EXTERNAL INCLUDES +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include + +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& 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& indices, unsigned int v0, unsigned int v1, unsigned int v2 ) +{ + indices.PushBack( v0 ); + indices.PushBack( v1 ); + indices.PushBack( v2 ); +} + +bool CreateGeometry( const Vector& glyphs, + unsigned int numberOfGlyphs, + const Vector& 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 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 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 glyphs; + glyphs.Resize( numberOfGlyphs ); + + Vector positions; + positions.Resize( numberOfGlyphs ); + + Vector 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 index 0000000..0b7a44e --- /dev/null +++ b/dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.h @@ -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 + +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 index 0000000..81a2817 --- /dev/null +++ b/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.cpp @@ -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 + +// EXTERNAL INCLUDES +#include +#include + +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 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( 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( GetBaseObject() ); + + return impl.GetCurrentAtlas(); +} + +VectorBlobAtlas* VectorBlobAtlasShare::GetNewAtlas() +{ + VectorBlobAtlasShare::Impl& impl = static_cast( 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 index 0000000..a854089 --- /dev/null +++ b/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h @@ -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 + +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 index 0000000..360cedf --- /dev/null +++ b/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.cpp @@ -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 + +// EXTERNAL INCLUDES +#include + +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 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 index 0000000..13b226d --- /dev/null +++ b/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h @@ -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 +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include + +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__ diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index ab41790..f477c15 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -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; @@ -2556,7 +2570,10 @@ void Controller::ClearModelData() 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(); diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index 7e22134..44a0257 100644 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -115,6 +115,13 @@ public: 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. diff --git a/dali-toolkit/public-api/text/rendering-backend.h b/dali-toolkit/public-api/text/rendering-backend.h index 5640a83..97abfb8 100644 --- a/dali-toolkit/public-api/text/rendering-backend.h +++ b/dali-toolkit/public-api/text/rendering-backend.h @@ -30,7 +30,8 @@ namespace Text // 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; -- 2.7.4