Bitmap Font support for TextLabel. 62/202262/12
authorVictor Cebollada <v.cebollada@samsung.com>
Mon, 25 Mar 2019 14:31:03 +0000 (14:31 +0000)
committerVictor Cebollada <v.cebollada@samsung.com>
Wed, 3 Apr 2019 13:33:19 +0000 (14:33 +0100)
* The TextTypesetter supports glyphs from a bitmap font.

Change-Id: Ic8befd32368d9747953545d0c504599fa835c0fd
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
17 files changed:
automated-tests/resources/fonts/bitmap/u0030.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0031.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0032.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0033.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0034.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0035.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0036.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0037.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0038.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0039.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u003a.png [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Circular.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Typesetter.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
dali-toolkit/devel-api/text/bitmap-font.cpp
dali-toolkit/devel-api/text/bitmap-font.h
dali-toolkit/internal/text/rendering/text-typesetter.cpp

diff --git a/automated-tests/resources/fonts/bitmap/u0030.png b/automated-tests/resources/fonts/bitmap/u0030.png
new file mode 100644 (file)
index 0000000..1b0cc3c
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0030.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0031.png b/automated-tests/resources/fonts/bitmap/u0031.png
new file mode 100644 (file)
index 0000000..2c70e9c
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0031.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0032.png b/automated-tests/resources/fonts/bitmap/u0032.png
new file mode 100644 (file)
index 0000000..2ed2d75
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0032.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0033.png b/automated-tests/resources/fonts/bitmap/u0033.png
new file mode 100644 (file)
index 0000000..2cb1673
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0033.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0034.png b/automated-tests/resources/fonts/bitmap/u0034.png
new file mode 100644 (file)
index 0000000..99d72e1
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0034.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0035.png b/automated-tests/resources/fonts/bitmap/u0035.png
new file mode 100644 (file)
index 0000000..2780eae
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0035.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0036.png b/automated-tests/resources/fonts/bitmap/u0036.png
new file mode 100644 (file)
index 0000000..62e240f
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0036.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0037.png b/automated-tests/resources/fonts/bitmap/u0037.png
new file mode 100644 (file)
index 0000000..ae3790a
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0037.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0038.png b/automated-tests/resources/fonts/bitmap/u0038.png
new file mode 100644 (file)
index 0000000..e2b0d13
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0038.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0039.png b/automated-tests/resources/fonts/bitmap/u0039.png
new file mode 100644 (file)
index 0000000..2a3f481
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0039.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u003a.png b/automated-tests/resources/fonts/bitmap/u003a.png
new file mode 100644 (file)
index 0000000..a6ca724
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u003a.png differ
index 4c94126..9a6d206 100755 (executable)
@@ -185,7 +185,10 @@ int UtcDaliTextCircularBitmapFont(void)
   Dali::Toolkit::DevelText::BitmapFontDescription description;
   Dali::Toolkit::DevelText::Glyph glyph;
   glyph.url = "BitmapFontUrl";
-  glyph.utf8 = "BitmapFontUrl";
+  glyph.utf8[0u] = 0u;
+  glyph.utf8[1u] = 0u;
+  glyph.utf8[2u] = 0u;
+  glyph.utf8[3u] = 0u;
   glyph.ascender = 1.f;
   glyph.descender = 1.f;
   description.glyphs.push_back( glyph );
index 44136a7..8ec03d6 100644 (file)
@@ -28,6 +28,8 @@
 #include <dali-toolkit/internal/text/rendering/view-model.h>
 #include <dali-toolkit/internal/text/text-controller.h>
 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
+#include <dali-toolkit/devel-api/text/bitmap-font.h>
 
 using namespace Dali;
 using namespace Toolkit;
@@ -196,3 +198,53 @@ int UtcDaliTextTypesetterVerticalLineAlignment(void)
   tet_result(TET_PASS);
   END_TEST;
 }
+
+int UtcDaliTextTypesetterBitmapFont(void)
+{
+  tet_infoline("UtcDaliTextTypesetterBitmapFont ");
+  ToolkitTestApplication application;
+
+  DevelText::BitmapFontDescription fontDescription;
+  fontDescription.name = "Digits";
+  fontDescription.underlinePosition = 0.f;
+  fontDescription.underlineThickness = 0.f;
+  fontDescription.isColorFont = true;
+
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0031.png", "0", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0032.png", "1", 34.f, 0.f } );
+
+  TextAbstraction::BitmapFont bitmapFont;
+  DevelText::CreateBitmapFont( fontDescription, bitmapFont );
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.GetFontId( bitmapFont );
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Configures the text controller similarly to the text-label.
+  ConfigureTextLabel( controller );
+
+  // Sets the text.
+  controller->SetMarkupProcessorEnabled( true );
+  controller->SetText( "<font family='Digits'><color 'value'='red'>0</color></font>" );
+
+  // Creates the text's model and relais-out the text.
+  const Size relayoutSize( 31.f, 34.f );
+  controller->Relayout( relayoutSize );
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr renderingController = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( renderingController );
+
+  controller->Relayout( relayoutSize );
+
+  // Renders the text and creates the final bitmap.
+  auto bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
+
+  DALI_TEST_EQUALS( 31u, bitmap.GetWidth(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 34u, bitmap.GetHeight(), TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
index 493655d..96fcb63 100755 (executable)
@@ -24,6 +24,8 @@
 #include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
 #include <dali-toolkit/devel-api/controls/text-controls/text-style-properties-devel.h>
 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
+#include <dali-toolkit/devel-api/text/bitmap-font.h>
 
 using namespace Dali;
 using namespace Toolkit;
@@ -1419,3 +1421,50 @@ int UtcDaliToolkitTextlabelVerticalLineAlignment(void)
 
   END_TEST;
 }
+
+int UtcDaliToolkitTextLabelBitmapFont(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelBitmapFont");
+
+  DevelText::BitmapFontDescription fontDescription;
+  fontDescription.name = "Digits";
+  fontDescription.underlinePosition = 0.f;
+  fontDescription.underlineThickness = 0.f;
+
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0030.png", ":", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0031.png", "0", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0032.png", "1", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0033.png", "2", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0034.png", "3", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0035.png", "4", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0036.png", "5", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0037.png", "6", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0038.png", "7", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0039.png", "8", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u003a.png", "9", 34.f, 0.f } );
+
+  TextAbstraction::BitmapFont bitmapFont;
+  DevelText::CreateBitmapFont( fontDescription, bitmapFont );
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.GetFontId( bitmapFont );
+
+  TextLabel label = TextLabel::New();
+
+  label.SetProperty( TextLabel::Property::TEXT, "0123456789:" );
+  label.SetProperty( TextLabel::Property::FONT_FAMILY, "Digits" );
+
+  // The text has been laid out with the bitmap font if the natural size is the sum of all the width (322) and 34 height.
+  DALI_TEST_EQUALS( label.GetNaturalSize(), Vector3(322.f, 34.f, 0.f), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( label );
+
+  application.SendNotification();
+  application.Render();
+
+  // The text has been rendered if the height of the text-label is the height of the line.
+  DALI_TEST_EQUALS( label.GetCurrentSize().height, 34.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  END_TEST;
+}
index 1e0e9c6..6c22e44 100755 (executable)
 #include <dali-toolkit/devel-api/text/bitmap-font.h>
 
 // EXTERNAL INCLUDE
-#include <dali/public-api/common/dali-vector.h>
 #include <dali/devel-api/text-abstraction/bitmap-font.h>
+#include <cstring>
 
 // INTERNAL INCLUDE
 #include <dali-toolkit/internal/text/character-set-conversion.h>
-#include <dali-toolkit/internal/text/text-definitions.h>
-
 
 namespace Dali
 {
 
 namespace Toolkit
 {
-using namespace Text;
+
 namespace DevelText
 {
 
 Glyph::Glyph()
 : url{},
-  utf8{ 0u },
+  utf8{},
   ascender{ 0.f },
   descender{ 0.f }
 {}
 
+Glyph::Glyph( const std::string& url, const std::string utf8Character, float ascender, float descender )
+: url{ url },
+  utf8{},
+  ascender{ ascender },
+  descender{ descender }
+{
+  DALI_ASSERT_DEBUG( utf8Character.size() <= 4u );
+
+  std::copy( utf8Character.begin(), utf8Character.end(), utf8 );
+}
+
 Glyph::~Glyph()
 {}
 
@@ -62,20 +71,14 @@ void CreateBitmapFont( const BitmapFontDescription& description, TextAbstraction
   bitmapFont.name = description.name;
   bitmapFont.underlinePosition = description.underlinePosition;
   bitmapFont.underlineThickness = description.underlineThickness;
+  bitmapFont.isColorFont = description.isColorFont;
 
   for( const auto& glyph : description.glyphs )
   {
-    // 1) Convert to utf32
-    Vector<Character> utf32;
-    utf32.Resize( glyph.utf8.size() );
-
-    const uint32_t numberOfCharacters = ( glyph.utf8.size() == 0 ) ? 0 :
-        Text::Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( glyph.utf8.c_str() ),
-                           glyph.utf8.size(),
-                           &utf32[0u] );
-    utf32.Resize( numberOfCharacters );
+    uint32_t c = 0u;
+    Text::Utf8ToUtf32( glyph.utf8, Text::GetUtf8Length( glyph.utf8[0u] ), &c );
 
-    TextAbstraction::BitmapGlyph bitmapGlyph( glyph.url, utf32[0u], glyph.ascender, glyph.descender );
+    TextAbstraction::BitmapGlyph bitmapGlyph( glyph.url, c, glyph.ascender, glyph.descender );
 
     bitmapFont.glyphs.push_back( std::move( bitmapGlyph ) );
   }
index ca068b4..0d463df 100755 (executable)
@@ -52,14 +52,26 @@ struct DALI_TOOLKIT_API Glyph
   Glyph();
 
   /**
+   * @brief Constructor.
+   *
+   * Initialize the members with the given values.
+   *
+   * @param[in] url The url of the bitmap for that glyph.
+   * @param[in] utf8 The utf8 codification of the glyph.
+   * @param[in] ascender The ascender of the glyph.
+   * @param[in] descender The descender of the glyph.
+   */
+  Glyph( const std::string& url, const std::string utf8, float ascender, float descender );
+
+  /**
    * @brief Default destructor.
    */
   ~Glyph();
 
-  std::string url;  ///< The url of the glyph.
-  std::string utf8; ///< the glyph encoded in utf8
-  float ascender;   ///< The ascender. The distance from the base line to the top of the glyph.
-  float descender;  ///< The descender. The distance from the base line to the bottom of the glyph.
+  std::string url; ///< The url of the glyph.
+  uint8_t utf8[4]; ///< the glyph encoded in utf8
+  float ascender;  ///< The ascender. The distance from the base line to the top of the glyph.
+  float descender; ///< The descender. The distance from the base line to the bottom of the glyph.
 };
 
 /**
@@ -83,6 +95,7 @@ struct DALI_TOOLKIT_API BitmapFontDescription
   std::string name;          ///< Name of the font.
   float underlinePosition;   ///< The position of the underline from the base line.
   float underlineThickness;  ///< The thickness of the underline.
+  bool isColorFont:1;        ///< Whether the glyphs of this font have their own colors.
 };
 
 /**
index de6b712..20ea5f7 100755 (executable)
@@ -80,7 +80,10 @@ void TypesetGlyph( GlyphData& data,
   if ( Pixel::RGBA8888 == pixelFormat )
   {
     // Whether the given glyph is a color one.
-    const bool isColorGlyph = Pixel::BGRA8888 == data.glyphBitmap.format;
+    const bool isColorGlyph = data.glyphBitmap.isColorEmoji || data.glyphBitmap.isColorBitmap;
+    const uint32_t glyphPixelSize = Pixel::GetBytesPerPixel( data.glyphBitmap.format );
+    const uint32_t alphaIndex = glyphPixelSize - 1u;
+    const bool swapChannelsBR = Pixel::BGRA8888 == data.glyphBitmap.format;
 
     // Pointer to the color glyph if there is one.
     const uint32_t* const colorGlyphBuffer = isColorGlyph ? reinterpret_cast<uint32_t*>( data.glyphBitmap.buffer ) : NULL;
@@ -88,6 +91,8 @@ void TypesetGlyph( GlyphData& data,
     // Initial vertical offset.
     const int yOffset = data.verticalOffset + position->y;
 
+    uint32_t* bitmapBuffer = reinterpret_cast< uint32_t* >( data.bitmapBuffer.GetBuffer() );
+
     // Traverse the pixels of the glyph line per line.
     for( int lineIndex = 0, glyphHeight = static_cast<int>( data.glyphBitmap.height ); lineIndex < glyphHeight; ++lineIndex )
     {
@@ -110,11 +115,9 @@ void TypesetGlyph( GlyphData& data,
           continue;
         }
 
-        uint32_t* bitmapBuffer = reinterpret_cast< uint32_t* >( data.bitmapBuffer.GetBuffer() );
-
         if( isColorGlyph )
         {
-          // Retrieves the color from the color glyph. The format is BGRA8888.
+          // Retrieves the color from the color glyph.
           uint32_t packedColorGlyph = *( colorGlyphBuffer + glyphBufferOffset + index );
           uint8_t* packedColorGlyphBuffer = reinterpret_cast<uint8_t*>( &packedColorGlyph );
 
@@ -129,7 +132,7 @@ void TypesetGlyph( GlyphData& data,
           }
           else
           {
-            uint8_t colorAlpha = static_cast<uint8_t>( color->a * static_cast<float>( *( packedColorGlyphBuffer + 3u ) ) );
+            const uint8_t colorAlpha = static_cast<uint8_t>( color->a * static_cast<float>( *( packedColorGlyphBuffer + 3u ) ) );
             *( packedColorGlyphBuffer + 3u ) = colorAlpha;
 
             if( Typesetter::STYLE_SHADOW == style )
@@ -141,11 +144,21 @@ void TypesetGlyph( GlyphData& data,
             }
             else
             {
-              std::swap( *packedColorGlyphBuffer, *( packedColorGlyphBuffer + 2u ) ); // Swap B and R.
+              if( swapChannelsBR )
+              {
+                std::swap( *packedColorGlyphBuffer, *( packedColorGlyphBuffer + 2u ) ); // Swap B and R.
+              }
 
               *( packedColorGlyphBuffer + 2u ) = ( *( packedColorGlyphBuffer + 2u ) * colorAlpha / 255 );
               *( packedColorGlyphBuffer + 1u ) = ( *( packedColorGlyphBuffer + 1u ) * colorAlpha / 255 );
                 *packedColorGlyphBuffer        = ( *( packedColorGlyphBuffer      ) * colorAlpha / 255 );
+
+              if( data.glyphBitmap.isColorBitmap )
+              {
+                *( packedColorGlyphBuffer + 2u ) = static_cast<uint8_t>( *( packedColorGlyphBuffer + 2u ) * color->b );
+                *( packedColorGlyphBuffer + 1u ) = static_cast<uint8_t>( *( packedColorGlyphBuffer + 1u ) * color->g );
+                  *packedColorGlyphBuffer        = static_cast<uint8_t>(   *packedColorGlyphBuffer * color->r );
+              }
             }
           }
 
@@ -160,7 +173,7 @@ void TypesetGlyph( GlyphData& data,
           uint8_t* packedColorBuffer = reinterpret_cast<uint8_t*>( &packedColor );
 
           // Update the alpha channel.
-          const uint8_t alpha = *( data.glyphBitmap.buffer + glyphBufferOffset + index );
+          const uint8_t alpha = *( data.glyphBitmap.buffer + glyphPixelSize * ( glyphBufferOffset + index ) + alphaIndex );
 
           // Copy non-transparent pixels only
           if ( alpha > 0u )
@@ -192,11 +205,15 @@ void TypesetGlyph( GlyphData& data,
   else
   {
     // Whether the given glyph is a color one.
-    const bool isColorGlyph = Pixel::BGRA8888 == data.glyphBitmap.format;
+    const bool isColorGlyph = data.glyphBitmap.isColorEmoji || data.glyphBitmap.isColorBitmap;
+    const uint32_t glyphPixelSize = Pixel::GetBytesPerPixel( data.glyphBitmap.format );
+    const uint32_t alphaIndex = glyphPixelSize - 1u;
 
     // Initial vertical offset.
     const int yOffset = data.verticalOffset + position->y;
 
+    uint8_t* bitmapBuffer = reinterpret_cast< uint8_t* >( data.bitmapBuffer.GetBuffer() );
+
     // Traverse the pixels of the glyph line per line.
     for( int lineIndex = 0, glyphHeight = static_cast<int>( data.glyphBitmap.height ); lineIndex < glyphHeight; ++lineIndex )
     {
@@ -219,12 +236,10 @@ void TypesetGlyph( GlyphData& data,
           continue;
         }
 
-        uint8_t* bitmapBuffer = reinterpret_cast< uint8_t* >( data.bitmapBuffer.GetBuffer() );
-
         if ( !isColorGlyph )
         {
           // Update the alpha channel.
-          const uint8_t alpha = *( data.glyphBitmap.buffer + glyphBufferOffset + index );
+          const uint8_t alpha = *( data.glyphBitmap.buffer + glyphPixelSize * ( glyphBufferOffset + index ) + alphaIndex );
 
           // Copy non-transparent pixels only
           if ( alpha > 0u )
@@ -236,7 +251,7 @@ void TypesetGlyph( GlyphData& data,
             // overwrite a previous bigger alpha with a smaller alpha (in order to avoid
             // semi-transparent gaps between joint glyphs with overlapped pixels, which could
             // happen, for example, in the RTL text when we copy glyphs from right to left).
-            *( bitmapBuffer + verticalOffset + xOffsetIndex ) = std::max( currentAlpha, alpha );
+            currentAlpha = std::max( currentAlpha, alpha );
           }
         }
       }