Text improvement 61/197561/26
authorVictor Cebollada <v.cebollada@samsung.com>
Mon, 16 Apr 2018 15:34:47 +0000 (16:34 +0100)
committerJoogab Yun <joogab.yun@samsung.com>
Tue, 19 Feb 2019 07:55:48 +0000 (16:55 +0900)
1. Circular text implementation.
 * Adds to dali-adaptor a back-end to render text with Cairo.
 * Add support for bitmap fonts.
 * Add support embedded Item.
2. Software italic/bold issues fixed.

Change-Id: I6491bdc19db789385f1928a99d63eaecb1c12959

35 files changed:
build/tizen/adaptor/Makefile.am
build/tizen/adaptor/configure.ac
dali/devel-api/adaptor-framework/pixel-buffer.cpp [changed mode: 0644->0755]
dali/devel-api/adaptor-framework/pixel-buffer.h
dali/devel-api/file.list
dali/devel-api/text-abstraction/bitmap-font.cpp [new file with mode: 0755]
dali/devel-api/text-abstraction/bitmap-font.h [new file with mode: 0755]
dali/devel-api/text-abstraction/font-client.cpp [changed mode: 0644->0755]
dali/devel-api/text-abstraction/font-client.h
dali/devel-api/text-abstraction/font-list.h
dali/devel-api/text-abstraction/font-metrics.cpp [changed mode: 0644->0755]
dali/devel-api/text-abstraction/font-metrics.h [changed mode: 0644->0755]
dali/devel-api/text-abstraction/glyph-info.cpp [changed mode: 0644->0755]
dali/devel-api/text-abstraction/glyph-info.h
dali/devel-api/text-abstraction/text-abstraction-definitions.h [changed mode: 0644->0755]
dali/devel-api/text-abstraction/text-abstraction.h [changed mode: 0644->0755]
dali/devel-api/text-abstraction/text-renderer-layout-helper.cpp [new file with mode: 0755]
dali/devel-api/text-abstraction/text-renderer-layout-helper.h [new file with mode: 0755]
dali/devel-api/text-abstraction/text-renderer.cpp [new file with mode: 0755]
dali/devel-api/text-abstraction/text-renderer.h [new file with mode: 0755]
dali/internal/imaging/common/image-operations.cpp
dali/internal/imaging/common/image-operations.h [changed mode: 0644->0755]
dali/internal/imaging/common/pixel-buffer-impl.cpp [changed mode: 0644->0755]
dali/internal/imaging/common/pixel-buffer-impl.h [changed mode: 0644->0755]
dali/internal/text/file.list [changed mode: 0644->0755]
dali/internal/text/text-abstraction/cairo-renderer.cpp [new file with mode: 0755]
dali/internal/text/text-abstraction/cairo-renderer.h [new file with mode: 0755]
dali/internal/text/text-abstraction/font-client-impl.cpp [changed mode: 0644->0755]
dali/internal/text/text-abstraction/font-client-impl.h [changed mode: 0644->0755]
dali/internal/text/text-abstraction/font-client-plugin-impl.cpp [changed mode: 0644->0755]
dali/internal/text/text-abstraction/font-client-plugin-impl.h [changed mode: 0644->0755]
dali/internal/text/text-abstraction/shaping-impl.cpp [changed mode: 0644->0755]
dali/internal/text/text-abstraction/text-renderer-impl.cpp [new file with mode: 0755]
dali/internal/text/text-abstraction/text-renderer-impl.h [new file with mode: 0755]
packaging/dali-adaptor.spec

index 24570db..8a79d7d 100644 (file)
@@ -436,6 +436,7 @@ LIBDALI_ADAPTOR_LA_CXXFLAGS = \
                       $(OPENGLES20_CFLAGS) \
                       $(FREETYPE_CFLAGS) \
                       $(FONTCONFIG_CFLAGS) \
+                      $(CAIRO_CFLAGS) \
                       $(PNG_CFLAGS) \
                       $(DLOG_CFLAGS) \
                       $(VCONF_CFLAGS) \
@@ -465,6 +466,7 @@ LIBDALI_ADAPTOR_LA_LIBADD = \
                       $(OPENGLES20_LIBS) \
                       $(FREETYPE_LIBS) \
                       $(FONTCONFIG_LIBS) \
+                      $(CAIRO_LIBS) \
                       $(PNG_LIBS) \
                       $(DLOG_LIBS) \
                       $(VCONF_LIBS) \
index ea05c8b..dba2891 100644 (file)
@@ -47,6 +47,7 @@ PKG_CHECK_MODULES(LIBCURL, libcurl)
 PKG_CHECK_MODULES(LIBCRYPTO, libcrypto)
 PKG_CHECK_MODULES(HARFBUZZ, harfbuzz)
 PKG_CHECK_MODULES(FRIBIDI, fribidi)
+PKG_CHECK_MODULES(CAIRO, cairo)
 PKG_CHECK_MODULES(EVAS, evas)
 PKG_CHECK_MODULES(TTRACE,  ttrace, AC_DEFINE(ENABLE_TTRACE, 1, [ttrace available]),
                   [ AC_MSG_NOTICE([Tizen Trace not avaiable]) ]
old mode 100644 (file)
new mode 100755 (executable)
index f8d12b2..8ba24a0
@@ -96,6 +96,11 @@ unsigned char* PixelBuffer::GetBuffer()
   return GetImplementation(*this).GetBuffer();
 }
 
+const unsigned char* const PixelBuffer::GetBuffer() const
+{
+  return GetImplementation(*this).GetConstBuffer();
+}
+
 void PixelBuffer::ApplyMask( PixelBuffer mask, float contentScale, bool cropToMask )
 {
   GetImplementation(*this).ApplyMask( GetImplementation( mask ), contentScale, cropToMask );
index a63a623..449bc02 100755 (executable)
@@ -134,6 +134,17 @@ public:
   unsigned char* GetBuffer();
 
   /**
+   * @brief Gets the pixel buffer. This is a pointer to the internal
+   * pixel buffer.
+   *
+   * @warning If there is no pixel buffer (e.g. this object has been
+   * converted to a PixelData), this method will return NULL.
+   *
+   * @return The pixel buffer, or NULL.
+   */
+  const unsigned char* const GetBuffer() const;
+
+  /**
    * @brief Gets the width of the buffer in pixels.
    *
    * @SINCE_1_2.46
index 9e05c21..f787144 100755 (executable)
@@ -84,16 +84,20 @@ devel_api_adaptor_framework_header_files = \
 
 devel_api_text_abstraction_src_files = \
    $(adaptor_devel_api_dir)/text-abstraction/bidirectional-support.cpp \
+   $(adaptor_devel_api_dir)/text-abstraction/bitmap-font.cpp \
    $(adaptor_devel_api_dir)/text-abstraction/font-client.cpp \
    $(adaptor_devel_api_dir)/text-abstraction/font-list.cpp \
    $(adaptor_devel_api_dir)/text-abstraction/font-metrics.cpp \
    $(adaptor_devel_api_dir)/text-abstraction/glyph-info.cpp \
    $(adaptor_devel_api_dir)/text-abstraction/script.cpp \
    $(adaptor_devel_api_dir)/text-abstraction/segmentation.cpp \
-   $(adaptor_devel_api_dir)/text-abstraction/shaping.cpp
+   $(adaptor_devel_api_dir)/text-abstraction/shaping.cpp \
+   $(adaptor_devel_api_dir)/text-abstraction/text-renderer.cpp \
+   $(adaptor_devel_api_dir)/text-abstraction/text-renderer-layout-helper.cpp
 
 text_abstraction_header_files = \
    $(adaptor_devel_api_dir)/text-abstraction/bidirectional-support.h \
+   $(adaptor_devel_api_dir)/text-abstraction/bitmap-font.h \
    $(adaptor_devel_api_dir)/text-abstraction/font-client.h \
    $(adaptor_devel_api_dir)/text-abstraction/font-list.h \
    $(adaptor_devel_api_dir)/text-abstraction/font-metrics.h \
@@ -102,5 +106,7 @@ text_abstraction_header_files = \
    $(adaptor_devel_api_dir)/text-abstraction/segmentation.h \
    $(adaptor_devel_api_dir)/text-abstraction/shaping.h \
    $(adaptor_devel_api_dir)/text-abstraction/text-abstraction.h \
-   $(adaptor_devel_api_dir)/text-abstraction/text-abstraction-definitions.h
+   $(adaptor_devel_api_dir)/text-abstraction/text-abstraction-definitions.h \
+   $(adaptor_devel_api_dir)/text-abstraction/text-renderer.h \
+   $(adaptor_devel_api_dir)/text-abstraction/text-renderer-layout-helper.h
 
diff --git a/dali/devel-api/text-abstraction/bitmap-font.cpp b/dali/devel-api/text-abstraction/bitmap-font.cpp
new file mode 100755 (executable)
index 0000000..4e17df5
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+BitmapGlyph::BitmapGlyph()
+: url{},
+  utf32{ 0u },
+  ascender{ 0.f },
+  descender{ 0.f }
+{}
+
+BitmapGlyph::BitmapGlyph( const std::string& url, GlyphIndex utf32, float ascender, float descender )
+: url{ url },
+  utf32{ utf32 },
+  ascender{ ascender },
+  descender{ descender }
+{}
+
+BitmapGlyph::~BitmapGlyph()
+{}
+
+BitmapFont::BitmapFont()
+: glyphs{},
+  name{},
+  ascender{ 0.f },
+  descender{ 0.f },
+  underlinePosition{ 0.f },
+  underlineThickness{ 1.f }
+{}
+
+BitmapFont::~BitmapFont()
+{}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
diff --git a/dali/devel-api/text-abstraction/bitmap-font.h b/dali/devel-api/text-abstraction/bitmap-font.h
new file mode 100755 (executable)
index 0000000..53bbec2
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef DALI_TEXT_ABSTRACTION_BITMAP_FONT_H
+#define DALI_TEXT_ABSTRACTION_BITMAP_FONT_H
+
+/*
+ * Copyright (c) 2019 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/common/dali-common.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/dali-adaptor-common.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+/**
+ * @brief Struct that stores the needed info to create a bitmap glyph.
+ *
+ * BitmapGlyph objects need to be added to a BitmapFont.
+ */
+struct DALI_ADAPTOR_API BitmapGlyph
+{
+  /**
+   * @brief Default constructor.
+   *
+   * Initialize the members to its defaults.
+   */
+  BitmapGlyph();
+
+  /**
+   * @brief Constructor.
+   *
+   * Initialize the members with the given values.
+   *
+   * @param[in] url The url of the bitmap for that glyph.
+   * @param[in] utf32 The utf32 codification of the glyph.
+   * @param[in] ascender The ascender of the glyph.
+   * @param[in] descender The descender of the glyph.
+   */
+  BitmapGlyph( const std::string& url, GlyphIndex utf32, float ascender, float descender );
+
+  /**
+   * @brief Default destructor.
+   */
+  ~BitmapGlyph();
+
+  std::string url;  ///< The url of the glyph's bitmap.
+  GlyphIndex utf32; ///< The id of the glyph encoded in utf32.
+  float ascender;   ///< The ascender in pixels. The distance from the base line to the top of the glyph.
+  float descender;  ///< The descender in pixels. The distance from the base line to the bottom of the glyph.
+};
+
+/**
+ * @brief Struct that stores the needed info to create a bitmap font.
+ *
+ * A bitmap font can be created by calling FontClient::GetFontId( const BitmapFont& ).
+ */
+struct DALI_ADAPTOR_API BitmapFont
+{
+  /**
+   * @brief Default constructor.
+   *
+   * Initialize the members to its defaults but the @e underlineThickness which is initilized to 1 pixel.
+   */
+  BitmapFont();
+
+  /**
+   * @brief Default destructor.
+   */
+  ~BitmapFont();
+
+  std::vector<BitmapGlyph> glyphs; ///< The glyphs of the font.
+  std::string name;                ///< The name of the font.
+  float ascender;                  ///< The ascender in pixels. Maximum ascender of all the glyphs.
+  float descender;                 ///< The descender in pixels. Minimum descender of all the glyphs.
+  float underlinePosition;         ///< The position in pixels of the underline from the base line.
+  float underlineThickness;        ///< The thickness in pixels of the underline.
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_TEXT_ABSTRACTION_BITMAP_FONT_H
old mode 100644 (file)
new mode 100755 (executable)
index 00b7528..653d11c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -28,6 +28,7 @@ namespace TextAbstraction
 {
 
 const PointSize26Dot6 FontClient::DEFAULT_POINT_SIZE = 768u; // 12*64
+const float FontClient::DEFAULT_ITALIC_ANGLE = 12.f * Dali::Math::PI_OVER_180; // FreeType documentation states the software italic is done by doing a horizontal shear of 12 degrees (file ftsynth.h).
 
 FontClient::GlyphBufferData::GlyphBufferData()
 : buffer( nullptr ),
@@ -146,6 +147,11 @@ FontId FontClient::GetFontId( const FontDescription& fontDescription,
                                              faceIndex );
 }
 
+FontId FontClient::GetFontId( const BitmapFont& bitmapFont )
+{
+  return GetImplementation(*this).GetFontId( bitmapFont );
+}
+
 bool FontClient::IsScalable( const FontPath& path )
 {
   return GetImplementation(*this).IsScalable( path );
@@ -167,6 +173,11 @@ void FontClient::GetFixedSizes( const FontDescription& fontDescription,
   GetImplementation(*this).GetFixedSizes( fontDescription, sizes );
 }
 
+bool FontClient::HasItalicStyle( FontId fontId ) const
+{
+  return GetImplementation(*this).HasItalicStyle( fontId );
+}
+
 void FontClient::GetFontMetrics( FontId fontId, FontMetrics& metrics )
 {
   GetImplementation(*this).GetFontMetrics( fontId, metrics );
@@ -182,9 +193,9 @@ bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType typ
   return GetImplementation(*this).GetGlyphMetrics( array, size, type, horizontal );
 }
 
-void FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItalic, bool softwareBold, GlyphBufferData& data, int outlineWidth )
+void FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, GlyphBufferData& data, int outlineWidth )
 {
-  GetImplementation(*this).CreateBitmap( fontId, glyphIndex, softwareItalic, softwareBold, data, outlineWidth );
+  GetImplementation(*this).CreateBitmap( fontId, glyphIndex, isItalicRequired, isBoldRequired, data, outlineWidth );
 }
 
 PixelData FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
@@ -212,6 +223,11 @@ bool FontClient::AddCustomFontDirectory( const FontPath& path )
   return GetImplementation(*this).AddCustomFontDirectory( path );
 }
 
+GlyphIndex FontClient::CreateEmbeddedItem(const EmbeddedItemDescription& description, Pixel::Format& pixelFormat)
+{
+  return GetImplementation(*this).CreateEmbeddedItem( description, pixelFormat);
+}
+
 FontClient::FontClient( Internal::FontClient* internal )
 : BaseHandle( internal )
 {
index c444eb8..4dbb5f5 100755 (executable)
@@ -2,7 +2,7 @@
 #define DALI_PLATFORM_TEXT_ABSTRACTION_FONT_CLIENT_H
 
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -35,6 +35,7 @@ namespace TextAbstraction
 
 struct FontMetrics;
 struct GlyphInfo;
+struct BitmapFont;
 
 namespace Internal DALI_INTERNAL
 {
@@ -64,6 +65,7 @@ class DALI_ADAPTOR_API FontClient : public BaseHandle
 {
 public:
   static const PointSize26Dot6 DEFAULT_POINT_SIZE; ///< The default point size.
+  static const float DEFAULT_ITALIC_ANGLE;         ///< The default software italic angle in radians.
 
   /**
    * @brief Struct used to retrieve the glyph's bitmap.
@@ -88,6 +90,17 @@ public:
     Pixel::Format  format; ///< The pixel's format of the bitmap.
   };
 
+  /**
+   * @brief Used to load an embedded item into the font client.
+   */
+  struct EmbeddedItemDescription
+  {
+    std::string       url;               ///< The url path of the image.
+    unsigned int      width;             ///< The width of the item.
+    unsigned int      height;            ///< The height of the item.
+    ColorBlendingMode colorblendingMode; ///< Whether the color of the image is multiplied by the color of the text.
+  };
+
 public:
 
   /**
@@ -273,6 +286,15 @@ public:
                     FaceIndex faceIndex = 0 );
 
   /**
+   * @brief Retrieves a unique font identifier for a given bitmap font.
+   *
+   * @param[in] bitmapFont A bitmap font.
+   *
+   * @return A valid font identifier, or zero if no bitmap font is created.
+   */
+  FontId GetFontId( const BitmapFont& bitmapFont );
+
+  /**
    * @brief Check to see if a font is scalable.
    *
    * @param[in] path The path to a font file.
@@ -310,6 +332,15 @@ public:
   void GetFixedSizes( const FontDescription& fontDescription,
                       Dali::Vector< PointSize26Dot6 >& sizes );
 
+  /**
+   * @brief Whether the font has Italic style.
+   *
+   * @param[in] fontId The font identifier.
+   *
+   * @return true if the font has italic style.
+   */
+  bool HasItalicStyle( FontId fontId ) const;
+
   ////////////////////////////////////////
   // Font metrics, glyphs and bitmaps.
   ////////////////////////////////////////
@@ -351,14 +382,14 @@ public:
    *
    * @note The caller is responsible for deallocating the bitmap data @p data.buffer using delete[].
    *
-   * @param[in]  fontId          The identifier of the font.
-   * @param[in]  glyphIndex      The index of a glyph within the specified font.
-   * @param[in]  softwareItalic  Whether glyph needs software support to draw italic style.
-   * @param[in]  softwareBold    Whether glyph needs software support to draw bold style.
-   * @param[out] data            The bitmap data.
-   * @param[in]  outlineWidth    The width of the glyph outline in pixels.
+   * @param[in]  fontId           The identifier of the font.
+   * @param[in]  glyphIndex       The index of a glyph within the specified font.
+   * @param[in]  isItalicRequired Whether the glyph requires italic style.
+   * @param[in]  isBoldRequired   Whether the glyph requires bold style.
+   * @param[out] data             The bitmap data.
+   * @param[in]  outlineWidth     The width of the glyph outline in pixels.
    */
-  void CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItalic, bool softwareBold, GlyphBufferData& data, int outlineWidth );
+  void CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, GlyphBufferData& data, int outlineWidth );
 
   /**
    * @brief Create a bitmap representation of a glyph.
@@ -417,6 +448,21 @@ public:
    */
   bool AddCustomFontDirectory( const FontPath& path );
 
+  /**
+   * @brief Creates and stores an embedded item and it's metrics.
+   *
+   * If in the @p description there is a non empty url, it calls Dali::LoadImageFromFile() internally.
+   * If in the @p description there is a url and @e width or @e height are zero it stores the default size. Otherwise the image is resized.
+   * If the url in the @p description is empty it stores the size.
+   *
+   * @param[in] description The description of the embedded item.
+   * @param[out] pixelFormat The pixel format of the image.
+   *
+   * return The index within the vector of embedded items.
+   */
+  GlyphIndex CreateEmbeddedItem( const EmbeddedItemDescription& description, Pixel::Format& pixelFormat);
+
+
 public: // Not intended for application developers
   /**
    * @brief This constructor is used by FontClient::Get().
index 2e76ad1..65c8a5a 100755 (executable)
@@ -1,8 +1,8 @@
-#ifndef __DALI_TEXT_ABSTRACTION_FONT_LIST_H__
-#define __DALI_TEXT_ABSTRACTION_FONT_LIST_H__
+#ifndef DALI_TEXT_ABSTRACTION_FONT_LIST_H
+#define DALI_TEXT_ABSTRACTION_FONT_LIST_H
 
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -139,12 +139,20 @@ namespace FontSlant
 
 struct FontDescription
 {
+  enum Type
+  {
+    INVALID,     ///< Not valid font.
+    FACE_FONT,   ///< A face font.
+    BITMAP_FONT, ///< A bitmap font. Each glyph has a url with the bitmap.
+  };
+
   FontDescription()
   : path(),
     family(),
     width( FontWidth::NONE ),
     weight( FontWeight::NONE ),
-    slant( FontSlant::NONE )
+    slant( FontSlant::NONE ),
+    type( INVALID )
   {}
 
   ~FontDescription()
@@ -155,6 +163,7 @@ struct FontDescription
   FontWidth::Type  width;  ///< The font's width.
   FontWeight::Type weight; ///< The font's weight.
   FontSlant::Type  slant;  ///< The font's slant.
+  Type             type;   ///< The type of font.
 };
 
 typedef std::vector<FontDescription> FontList;
@@ -165,4 +174,4 @@ DALI_ADAPTOR_API std::ostream& operator<<( std::ostream& o, const FontList& font
 
 } // namespace Dali
 
-#endif // __DALI_TEXT_ABSTRACTION_FONT_LIST_H__
+#endif // DALI_TEXT_ABSTRACTION_FONT_LIST_H
old mode 100644 (file)
new mode 100755 (executable)
index 1edff6d..e192a44
@@ -25,11 +25,11 @@ namespace TextAbstraction
 {
 
 FontMetrics::FontMetrics()
-: ascender( 0.f ),
-  descender( 0.f ),
-  height( 0.f ),
-  underlinePosition( 0.f ),
-  underlineThickness( 0.f )
+: ascender{ 0.f },
+  descender{ 0.f },
+  height{ 0.f },
+  underlinePosition{ 0.f },
+  underlineThickness{ 0.f }
 {
 }
 
@@ -38,11 +38,11 @@ FontMetrics::FontMetrics( float ascenderPixels,
                           float heightPixels,
                           float underlinePositionPixels,
                           float underlineThicknessPixels )
-: ascender( ascenderPixels ),
-  descender( descenderPixels ),
-  height( heightPixels ),
-  underlinePosition( underlinePositionPixels ),
-  underlineThickness( underlineThicknessPixels )
+: ascender{ ascenderPixels },
+  descender{ descenderPixels },
+  height{ heightPixels },
+  underlinePosition{ underlinePositionPixels },
+  underlineThickness{ underlineThicknessPixels }
 {
 }
 
old mode 100644 (file)
new mode 100755 (executable)
index 0edbce2..f314735
@@ -1,8 +1,8 @@
-#ifndef __DALI_TEXT_ABSTRACTION_FONT_METRICS_H__
-#define __DALI_TEXT_ABSTRACTION_FONT_METRICS_H__
+#ifndef DALI_TEXT_ABSTRACTION_FONT_METRICS_H
+#define DALI_TEXT_ABSTRACTION_FONT_METRICS_H
 
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -44,7 +44,7 @@ struct DALI_ADAPTOR_API FontMetrics
                float descenderPixels,
                float heightPixels,
                float underlinePositionPixels,
-               float underlinePositionThickness );
+               float underlineThicknessPixels );
 
   float ascender;             ///< The ascender in pixels.
   float descender;            ///< The descender in pixels.
@@ -57,4 +57,4 @@ struct DALI_ADAPTOR_API FontMetrics
 
 } // TextAbstraction
 
-#endif //__DALI_TEXT_ABSTRACTION_FONT_METRICS_H__
+#endif //DALI_TEXT_ABSTRACTION_FONT_METRICS_H
old mode 100644 (file)
new mode 100755 (executable)
index 898a2d5..1e87831
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -25,30 +25,30 @@ namespace TextAbstraction
 {
 
 GlyphInfo::GlyphInfo()
-: fontId( 0 ),
-  index( 0 ),
-  width( 0 ),
-  height( 0 ),
-  xBearing( 0 ),
-  yBearing( 0 ),
-  advance( 0 ),
-  scaleFactor( 0 ),
-  softwareItalic(false),
-  softwareBold(false)
+: fontId{ 0u },
+  index{ 0u },
+  width( 0.f ),
+  height{ 0.f },
+  xBearing{ 0.f },
+  yBearing{ 0.f },
+  advance{ 0.f },
+  scaleFactor{ 0.f },
+  isItalicRequired{ false },
+  isBoldRequired{ false }
 {
 }
 
 GlyphInfo::GlyphInfo( FontId font, GlyphIndex i )
-: fontId( font ),
-  index( i ),
-  width( 0 ),
-  height( 0 ),
-  xBearing( 0 ),
-  yBearing( 0 ),
-  advance( 0 ),
-  scaleFactor( 0 ),
-  softwareItalic(false),
-  softwareBold(false)
+: fontId{ font },
+  index{ i },
+  width( 0.f ),
+  height{ 0.f },
+  xBearing{ 0.f },
+  yBearing{ 0.f },
+  advance{ 0.f },
+  scaleFactor{ 0.f },
+  isItalicRequired{ false },
+  isBoldRequired{ false }
 {
 }
 
index 772c78f..fbc8fec 100755 (executable)
@@ -1,8 +1,8 @@
-#ifndef __DALI_TEXT_ABSTRACTION_GLYPH_INFO_H__
-#define __DALI_TEXT_ABSTRACTION_GLYPH_INFO_H__
+#ifndef DALI_TEXT_ABSTRACTION_GLYPH_INFO_H
+#define DALI_TEXT_ABSTRACTION_GLYPH_INFO_H
 
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -44,20 +44,20 @@ struct DALI_ADAPTOR_API GlyphInfo
    */
   GlyphInfo( FontId font, GlyphIndex i );
 
-  FontId fontId;       ///< Identifies the font containing the glyph
-  GlyphIndex index;    ///< Uniquely identifies a glyph for a given FontId
-  float width;         ///< The width of the glyph
-  float height;        ///< The height of the glyph
-  float xBearing;      ///< The distance from the cursor position to the leftmost border of the glyph
-  float yBearing;      ///< The distance from the baseline to the topmost border of the glyph
-  float advance;       ///< The distance to move the cursor for this glyph
-  float scaleFactor;   ///< The scaling applied (fixed-size fonts only)
-  bool softwareItalic; ///< Whether glyph needs software support to draw italic style
-  bool softwareBold;   ///< Whether glyph needs software support to draw bold style
+  FontId fontId;           ///< Identifies the font containing the glyph
+  GlyphIndex index;        ///< Uniquely identifies a glyph for a given FontId
+  float width;             ///< The width of the glyph
+  float height;            ///< The height of the glyph
+  float xBearing;          ///< The distance from the cursor position to the leftmost border of the glyph
+  float yBearing;          ///< The distance from the baseline to the topmost border of the glyph
+  float advance;           ///< The distance to move the cursor for this glyph
+  float scaleFactor;       ///< The scaling applied (fixed-size fonts only)
+  bool isItalicRequired:1; ///< Whether the italic style is required.
+  bool isBoldRequired:1;   ///< Whether the bold style is required.
 };
 
 } // Dali
 
 } // TextAbstraction
 
-#endif //__DALI_TEXT_ABSTRACTION_GLYPH_INFO_H__
+#endif //DALI_TEXT_ABSTRACTION_GLYPH_INFO_H
old mode 100644 (file)
new mode 100755 (executable)
index a6be687..c8c346a
@@ -38,6 +38,7 @@ typedef uint32_t BidiInfoIndex;      ///< Index to the bidirectional info for a
 typedef char     LineBreakInfo;      ///< Line break info (must break, allow break, no break).
 typedef char     WordBreakInfo;      ///< Word break info (break, no break).
 typedef bool     CharacterDirection; ///< The character's direction: @e false is left to right, @e true is right to left.
+typedef uint32_t ColorIndex;         ///< An index into an array of colors.
 
 /**
  * @brief Enumerates the possible line break info values.
@@ -72,6 +73,15 @@ struct VectorBlob
   unsigned char a;
 };
 
+/**
+* @brief Defines how a color is blended.
+*/
+enum class ColorBlendingMode
+{
+  NONE,     ///< No blend.
+  MULTIPLY  ///< The color is multiplied by another one.
+};
+
 } // namespace TextAbstraction
 
 } // namespace Dali
old mode 100644 (file)
new mode 100755 (executable)
index adc9b2b..3a9309e
@@ -1,8 +1,8 @@
-#ifndef __DALI_TEXT_ABSTRACTION_H__
-#define __DALI_TEXT_ABSTRACTION_H__
+#ifndef DALI_TEXT_ABSTRACTION_H
+#define DALI_TEXT_ABSTRACTION_H
 
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -19,6 +19,7 @@
  */
 
 #include <dali/devel-api/text-abstraction/bidirectional-support.h>
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
 #include <dali/devel-api/text-abstraction/font-client.h>
 #include <dali/devel-api/text-abstraction/font-metrics.h>
 #include <dali/devel-api/text-abstraction/glyph-info.h>
@@ -26,4 +27,4 @@
 #include <dali/devel-api/text-abstraction/segmentation.h>
 #include <dali/devel-api/text-abstraction/shaping.h>
 
-#endif //__DALI_TEXT_ABSTRACTION_H__
+#endif // DALI_TEXT_ABSTRACTION_H
diff --git a/dali/devel-api/text-abstraction/text-renderer-layout-helper.cpp b/dali/devel-api/text-abstraction/text-renderer-layout-helper.cpp
new file mode 100755 (executable)
index 0000000..b5a3eb4
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali/devel-api/text-abstraction/text-renderer-layout-helper.h>
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+void TransformToArcClockwise( const CircularTextParameters& parameters, double& x, double& y )
+{
+  double radius = parameters.radius;
+  double angle = parameters.beginAngle;
+
+  angle -= parameters.invRadius * x;
+
+  radius -= y;
+  x =  radius * cos( angle );
+  y = -radius * sin( angle );
+
+  x += parameters.centerX;
+  y += parameters.centerY;
+}
+
+void TransformToArcAntiClockwise( const CircularTextParameters& parameters, double& x, double& y )
+{
+  double radius = parameters.radius;
+  double angle = parameters.beginAngle;
+
+  angle += parameters.invRadius * x;
+
+  radius += y;
+  x = radius * cos( angle );
+  y = radius * sin( -angle );
+
+  x += parameters.centerX;
+  y += parameters.centerY;
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/text-renderer-layout-helper.h b/dali/devel-api/text-abstraction/text-renderer-layout-helper.h
new file mode 100755 (executable)
index 0000000..95921a1
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef DALI_PLATFORM_TEXT_ABSTRACTION_TEXT_RENDERER_LAYOUT_HELPER_H
+#define DALI_PLATFORM_TEXT_ABSTRACTION_TEXT_RENDERER_LAYOUT_HELPER_H
+
+/*
+ * Copyright (c) 2019 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/common/dali-common.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+/**
+ * @brief Parameters used to transform the vertices of the glyphs to wrap a circular path.
+ */
+struct DALI_ADAPTOR_API CircularTextParameters
+{
+  CircularTextParameters()
+  : centerX{ 0.0 },
+    centerY{ 0.0 },
+    radius{ 0.0 },
+    invRadius{ 0.0 },
+    beginAngle{ 0.0 },
+    isClockwise{ true }
+  {}
+
+  double centerX;     ///< The 'x' center of the circular path.
+  double centerY;     ///< The 'y' center of the circular path.
+  double radius;      ///< The radius in pixels.
+  double invRadius;   ///< 1.0 / radius.
+  double beginAngle;  ///< The angle in radians where the circular text begins.
+  bool isClockwise:1; ///< Whether the circular text layout is clockwise.
+};
+
+/**
+ * @brief Transforms a vertex to wrap a clockwise circular path.
+ *
+ * @param[in] parameters The parameters of the circular path.
+ * @param[in,out] x The 'x' coordinate of the vertex.
+ * @param[in,out] y The 'y' coordinate of the vertex.
+ */
+DALI_ADAPTOR_API void TransformToArcClockwise( const CircularTextParameters& parameters, double& x, double& y );
+
+/**
+ * @brief Transforms a vertex to wrap an anti clockwise circular path.
+ *
+ * @param[in] parameters The parameters of the circular path.
+ * @param[in,out] x The 'x' coordinate of the vertex.
+ * @param[in,out] y The 'y' coordinate of the vertex.
+ */
+DALI_ADAPTOR_API void TransformToArcAntiClockwise( const CircularTextParameters& parameters, double& x, double& y );
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_PLATFORM_TEXT_ABSTRACTION_TEXT_RENDERER_LAYOUT_HELPER_H
diff --git a/dali/devel-api/text-abstraction/text-renderer.cpp b/dali/devel-api/text-abstraction/text-renderer.cpp
new file mode 100755 (executable)
index 0000000..a4a68a6
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+* Copyright (c) 2019 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/devel-api/text-abstraction/text-renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text/text-abstraction/text-renderer-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+TextRenderer::TextRenderer()
+{
+}
+
+TextRenderer::~TextRenderer()
+{
+}
+
+TextRenderer TextRenderer::Get()
+{
+  return Internal::TextRenderer::Get();
+}
+
+Devel::PixelBuffer TextRenderer::Render(const Parameters& parameters)
+{
+  return GetImplementation(*this).Render(parameters);
+}
+
+TextRenderer::TextRenderer(Internal::TextRenderer *impl)
+: BaseHandle(impl)
+{
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/text-renderer.h b/dali/devel-api/text-abstraction/text-renderer.h
new file mode 100755 (executable)
index 0000000..9babd32
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef DALI_TOOLKIT_TEXT_ABSTRACTION_TEXT_RENDERER_H
+#define DALI_TOOLKIT_TEXT_ABSTRACTION_TEXT_RENDERER_H
+
+/*
+ * Copyright (c) 2019 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/common/dali-vector.h>
+#include <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+  // Forward declaration
+  class TextRenderer;
+
+} // namespace Internal
+
+/**
+ * @brief Renders the given @e glyphs at the given @e positions into a pixel buffer.
+ *
+ * @note This class renders glyphs not characters.
+ *       Font selection, RTL reordering, shaping and layout
+ *       has to be done before calling the @e Render()
+ *       method of this class.
+ */
+class DALI_ADAPTOR_API TextRenderer : public BaseHandle
+{
+public:
+  /**
+   * @brief Parameters to render the text.
+   */
+  struct Parameters
+  {
+    /**
+     * @brief Enum with the possible pixel formats of the output pixel buffer.
+     */
+    enum PixelFormat
+    {
+      A8,      ///< Alpha channel, 8-bit color depth.
+      RGBA8888 ///< Red, Green, Blue and Alpha channels, 8-bit color depth per channel.
+    };
+
+    /**
+     * @brief Whether the circular layout is clockwise.
+     */
+    enum CircularLayout
+    {
+      CLOCKWISE,        ///< The text is laid clockwise on a circular path.
+      COUNTER_CLOCKWISE ///< The text is laid counter clockwise on a circular path.
+    };
+
+    /**
+     * @brief Parameters for the text renderer function.
+     */
+    Parameters( Vector<GlyphInfo>& glyphs,
+                Vector<Vector2>& positions,
+                Vector<Vector4>& colors,
+                Vector<ColorIndex>& colorIndices,
+                Vector<ColorBlendingMode>& blendingMode,
+                Vector<bool>& isEmoji )
+    : glyphs( glyphs ),
+      positions( positions ),
+      colors( colors ),
+      colorIndices( colorIndices ),
+      blendingMode( blendingMode ),
+      isEmoji( isEmoji ),
+      width{ 0u },
+      height{ 0u },
+      radius{ 0u },
+      circularWidth{ 0u },
+      circularHeight{ 0u },
+      centerX{ 0 },
+      centerY{ 0 },
+      beginAngle{ 0.f },
+      pixelFormat{ A8 },
+      circularLayout{ CLOCKWISE }
+    {}
+
+    Vector<GlyphInfo>& glyphs;               ///< The glyphs to be rendered.
+    Vector<Vector2>& positions;              ///< The position for each glyph.
+    Vector<Vector4>& colors;                 ///< Colors of the glyphs.
+    Vector<ColorIndex>& colorIndices;        ///< Indices to the vector of colors for each glyphs.
+    Vector<ColorBlendingMode>& blendingMode; ///< How each glyph is going to be blended with the color of the text.
+    Vector<bool>& isEmoji;                   ///< Whether each glyph is an emoji.
+    unsigned int width;                      ///< The width of the pixel buffer. @note Some implementations may change the width for performance reasons.
+    unsigned int height;                     ///< The height of the pixel buffer.
+    unsigned int radius;                     ///< The radius in pixels of the circular text.
+    unsigned int circularWidth;              ///< The width of the text laid out on an horizontal straight line.
+    unsigned int circularHeight;             ///< The height of the text laid out on an horizontal straight line.
+    int centerX;                             ///< The 'x' coordinate of the center. For circular layout.
+    int centerY;                             ///< The 'y' coordinate of the center. For circular layout.
+    float beginAngle;                        ///< The angle in radians where the circular text begins.
+    PixelFormat pixelFormat;                 ///< The pixel format of the pixel buffer.
+    CircularLayout circularLayout;           ///< The direction of the text's layout.
+  };
+
+public:
+
+  /**
+   * @brief Create an uninitialized TextRenderer handle.
+   *
+   */
+  TextRenderer();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~TextRenderer();
+
+  /**
+   * @brief Retrieve a handle to the TextRenderer instance.
+   *
+   * @return A handle to the TextRenderer.
+   */
+  static TextRenderer Get();
+
+  /**
+   * @brief Renders the given @e glyphs into a pixel buffer.
+   *
+   * @param[in] parameters Struct with the glyphs, positions and the size of the pixel buffer.
+   *
+   * @return The pixel buffer with the text rendered on it.
+   */
+  Devel::PixelBuffer Render(const Parameters& parameters);
+
+public: // Not intended for application developers.
+
+  /// @cond internal
+  /**
+   * @brief This constructor is used by TextRenderer::Get().
+   *
+   * @param[in] implementation A pointer to the internal text renderer object.
+   */
+  explicit DALI_INTERNAL TextRenderer(Internal::TextRenderer* implementation);
+  /// @endcond
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_ABSTRACTION_TEXT_RENDERER_H
index 662d775..ae88aef 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -2174,6 +2174,7 @@ void RotateByShear( const uint8_t* const pixelsIn,
 
     if( !fastRotationPerformed )
     {
+      DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "fast rotation failed\n");
       // The fast rotation failed.
       return;
     }
@@ -2195,6 +2196,7 @@ void RotateByShear( const uint8_t* const pixelsIn,
 
     if( !fastRotationPerformed )
     {
+      DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "fast rotation failed\n");
       // The fast rotation failed.
       return;
     }
@@ -2220,6 +2222,7 @@ void RotateByShear( const uint8_t* const pixelsIn,
 
     if( !fastRotationPerformed )
     {
+      DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "fast rotation failed\n");
       // The fast rotation failed.
       return;
     }
@@ -2265,6 +2268,8 @@ void RotateByShear( const uint8_t* const pixelsIn,
     widthOut = 0u;
     heightOut = 0u;
 
+    DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "malloc failed to allocate memory\n");
+
     // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Fast rotations'.
     // Nothing else to do if the memory allocation fails.
     return;
@@ -2301,6 +2306,7 @@ void RotateByShear( const uint8_t* const pixelsIn,
     widthOut = 0u;
     heightOut = 0u;
 
+    DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "malloc failed to allocate memory\n");
     // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'First Horizontal Skew'.
     // Nothing else to do if the memory allocation fails.
     return;
@@ -2337,6 +2343,7 @@ void RotateByShear( const uint8_t* const pixelsIn,
     widthOut = 0u;
     heightOut = 0u;
 
+    DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "malloc failed to allocate memory\n");
     // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Vertical Skew'.
     // Nothing else to do if the memory allocation fails.
     return;
@@ -2354,6 +2361,53 @@ void RotateByShear( const uint8_t* const pixelsIn,
   // @note Allocated memory by the last 'Horizontal Skew' has to be freed by the caller to this function.
 }
 
+void HorizontalShear( const uint8_t* const pixelsIn,
+                      unsigned int widthIn,
+                      unsigned int heightIn,
+                      unsigned int pixelSize,
+                      float radians,
+                      uint8_t*& pixelsOut,
+                      unsigned int& widthOut,
+                      unsigned int& heightOut )
+{
+  // Calculate the destination image dimensions.
+
+  const float absRadians = fabs( radians );
+
+  if( absRadians > Math::PI_4 )
+  {
+    // Can't shear more than 45 degrees.
+    widthOut = 0u;
+    heightOut = 0u;
+
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Can't shear more than 45 degrees (PI/4 radians). radians : %f\n", radians );
+    return;
+  }
+
+  widthOut = widthIn + static_cast<unsigned int>( absRadians * static_cast<float>( heightIn ) );
+  heightOut = heightIn;
+
+  // Allocate the buffer for the shear.
+  pixelsOut = static_cast<uint8_t*>( malloc( widthOut * heightOut * pixelSize ) );
+
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "malloc failed to allocate memory\n" );
+    return;
+  }
+
+  for( unsigned int y = 0u; y < heightOut; ++y )
+  {
+    const float shear = radians * ( ( radians >= 0.f ) ? ( 0.5f + static_cast<float>( y ) ) : ( 0.5f + static_cast<float>( y ) - static_cast<float>( heightOut ) ) );
+
+    const int intShear = static_cast<int>( floor( shear ) );
+    HorizontalSkew( pixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>( intShear ) );
+  }
+}
+
 } /* namespace Platform */
 } /* namespace Internal */
 } /* namespace Dali */
old mode 100644 (file)
new mode 100755 (executable)
index c78f8fe..6ae9ba1
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -15,8 +15,8 @@
  *
  */
 
-#ifndef DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_
-#define DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_
+#ifndef DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H
+#define DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H
 
 // EXTERNAL INCLUDES
 #include <stdint.h>
@@ -407,6 +407,33 @@ void RotateByShear( const uint8_t* const pixelsIn,
                     unsigned int& widthOut,
                     unsigned int& heightOut );
 
+/**
+ * @brief Applies to the input image a horizontal shear transformation.
+ *
+ * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
+ * separate buffer from the output buffer.
+ * @pre The maximun/minimum shear angle is +/-45 degrees (PI/4 around 0.79 radians).
+ *
+ * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
+ *
+ * @param[in] pixelsIn The input buffer.
+ * @param[in] widthIn The width of the input buffer.
+ * @param[in] heightIn The height of the input buffer.
+ * @param[in] pixelSize The size of the pixel.
+ * @param[in] radians The shear angle in radians.
+ * @param[out] pixelsOut The rotated output buffer.
+ * @param[out] widthOut The width of the output buffer.
+ * @param[out] heightOut The height of the output buffer.
+ */
+void HorizontalShear( const uint8_t* const pixelsIn,
+                      unsigned int widthIn,
+                      unsigned int heightIn,
+                      unsigned int pixelSize,
+                      float radians,
+                      uint8_t*& pixelsOut,
+                      unsigned int& widthOut,
+                      unsigned int& heightOut );
+
 /**@}*/
 
 /**
@@ -583,4 +610,4 @@ inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, u
 } /* namespace Internal */
 } /* namespace Dali */
 
-#endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_ */
+#endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H */
old mode 100644 (file)
new mode 100755 (executable)
index 3bcb4ef..85c5c8a
@@ -119,6 +119,11 @@ unsigned char* PixelBuffer::GetBuffer() const
   return mBuffer;
 }
 
+const unsigned char* const PixelBuffer::GetConstBuffer() const
+{
+  return mBuffer;
+}
+
 unsigned int PixelBuffer::GetBufferSize() const
 {
   return mBufferSize;
old mode 100644 (file)
new mode 100755 (executable)
index b0fe5ce..5c5c045
@@ -133,6 +133,11 @@ public:
   unsigned char* GetBuffer() const;
 
   /**
+   * @copydoc Devel::PixelBuffer::GetBuffer()
+   */
+  const unsigned char* const GetConstBuffer() const;
+
+  /**
    * Get the size of the buffer in bytes
    * @return The size of the buffer
    */
old mode 100644 (file)
new mode 100755 (executable)
index 52a9931..324102c
@@ -3,9 +3,11 @@
 # module: text, backend: common
 adaptor_text_common_src_files=\
     ${adaptor_text_dir}/text-abstraction/bidirectional-support-impl.cpp \
+    ${adaptor_text_dir}/text-abstraction/cairo-renderer.cpp \
     ${adaptor_text_dir}/text-abstraction/font-client-helper.cpp \
     ${adaptor_text_dir}/text-abstraction/font-client-impl.cpp \
     ${adaptor_text_dir}/text-abstraction/font-client-plugin-impl.cpp \
     ${adaptor_text_dir}/text-abstraction/segmentation-impl.cpp \
-    ${adaptor_text_dir}/text-abstraction/shaping-impl.cpp
+    ${adaptor_text_dir}/text-abstraction/shaping-impl.cpp \
+    ${adaptor_text_dir}/text-abstraction/text-renderer-impl.cpp
 
diff --git a/dali/internal/text/text-abstraction/cairo-renderer.cpp b/dali/internal/text/text-abstraction/cairo-renderer.cpp
new file mode 100755 (executable)
index 0000000..ea3a013
--- /dev/null
@@ -0,0 +1,869 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali/internal/text/text-abstraction/cairo-renderer.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/constants.h>
+#include <cairo.h>
+#include <cairo-ft.h>
+#include <cstring>
+#include <memory>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_STROKER_H
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/text-abstraction/text-renderer-layout-helper.h>
+#include <dali/integration-api/debug.h>
+#include <dali/internal/imaging/common/image-operations.h>
+#include <dali/internal/text/text-abstraction/font-client-impl.h>
+
+namespace
+{
+
+const float TO_FLOAT = 1.f / 255.f;
+const float TO_UCHAR = 255.f;
+const float TWO_PI = 2.f * Dali::Math::PI; ///< 360 degrees in radians
+
+/**
+ * @brief Run of glyphs that have the same style.
+ */
+struct GlyphRun
+{
+  GlyphRun()
+  : fontFace{ nullptr },
+    fontSize{ 0.0 },
+    glyphIndex{ 0u },
+    numberOfGlyphs{ 0u },
+    fontId{ 0u },
+    colorIndex{ 0u },
+    isItalicRequired{ false },
+    isBoldRequired{ false }
+  {}
+
+  FT_Face      fontFace;           ///< The font face used by the glyphs in the run.
+  double       fontSize;           ///< The font size used by the glyphs in the run. According the Cairo's documentation this is in user space units. It works if I set the size in pixels.
+  unsigned int glyphIndex;         ///< Index to the first glyph of the run.
+  unsigned int numberOfGlyphs;     ///< Number of glyphs in the run.
+  unsigned int fontId;             ///< The id of the font.
+  unsigned int colorIndex;         ///< The index to the color of the glyphs.
+  bool         isItalicRequired:1; ///< Whether the italic style is required.
+  bool         isBoldRequired:1;   ///< Whether the bold style is required.
+};
+
+/**
+ * @brief Helper struct used to destroy a bitmap buffer.
+ *
+ * The font client allocates a bitmap's buffer with the new operator.
+ * However, the PixelBuffer class allocates the buffer with the
+ * malloc() function and the Rotate() function which is intended
+ * for the PixelBuffer as well allocates memory with malloc().
+ *
+ * This struct keeps the type of allocation and uses the delete[]
+ * operator or the free() function to deallocate resources.
+ */
+struct GlyphBuffer
+{
+  enum DestructorType
+  {
+    FREE,
+    DELETE
+  };
+
+  GlyphBuffer( Dali::TextAbstraction::FontClient::GlyphBufferData& data, DestructorType type )
+  : data( data ),
+    type( type )
+  {
+  }
+
+  ~GlyphBuffer()
+  {
+    switch( type )
+    {
+      case FREE:
+      {
+        free( data.buffer );
+        break;
+      }
+      case DELETE:
+      {
+        delete[] data.buffer;
+      }
+    }
+  }
+
+  Dali::TextAbstraction::FontClient::GlyphBufferData& data;
+  DestructorType type;
+};
+
+/**
+ * @brief Creates a pixel buffer with all pixels set to transparent.
+ *
+ * @param[in] parameters Contains the width and height of the pixel buffer.
+ *
+ * @return The pixel buffer.
+ */
+Dali::Devel::PixelBuffer CreateVoidPixelBuffer( const Dali::TextAbstraction::TextRenderer::Parameters& parameters )
+{
+  Dali::Pixel::Format pixelFormat = parameters.pixelFormat == Dali::TextAbstraction::TextRenderer::Parameters::A8 ? Dali::Pixel::A8 : Dali::Pixel::RGBA8888;
+  Dali::Devel::PixelBuffer pixelBuffer = Dali::Devel::PixelBuffer::New( parameters.width,
+                                                                        parameters.height,
+                                                                        pixelFormat );
+
+  const unsigned int bufferSize = parameters.width * parameters.height * Dali::Pixel::GetBytesPerPixel( pixelFormat );
+  unsigned char* buffer = pixelBuffer.GetBuffer();
+  memset( buffer, 0, bufferSize );
+
+  return pixelBuffer;
+}
+
+/**
+ * @brief Wraps the vertices of glyphs laid out on a horizontal strainght line on a circular path.
+ *
+ * It copies the vertices from the extra cairo context created to lay out the text
+ * on a horizontal straight line to the cairo context used to render it.
+ *
+ * @param[in,out] cr The cairo context used to render the text.
+ * @param[in] circularCr The extra cairo context created to layout horizontal text.
+ * @param[in] parameters The parameters of the circular path.
+ */
+void WrapToCircularPath( cairo_t* cr, cairo_t* circularCr, const Dali::TextAbstraction::CircularTextParameters& parameters )
+{
+  bool first = true;
+
+  // Copy the path to get a cairo_path_t pointer used to iterate through all its items.
+  std::unique_ptr<cairo_path_t, void(*)(cairo_path_t*)> path( cairo_copy_path( circularCr ), cairo_path_destroy );
+
+  void ( *transformToArc )( const Dali::TextAbstraction::CircularTextParameters&, double&, double& );
+  transformToArc = parameters.isClockwise ? &Dali::TextAbstraction::TransformToArcClockwise : &Dali::TextAbstraction::TransformToArcAntiClockwise;
+
+  // Iterates through all the path items and transform each vertex to follow the circle.
+  // Transformed vertices are added to a new path in the 'cr' context (the one used to render the circular text)
+  for( int i = 0; i < path->num_data; i += path->data[i].header.length )
+  {
+    cairo_path_data_t* data = &path->data[i];
+
+    switch( data->header.type )
+    {
+      case CAIRO_PATH_MOVE_TO:
+      {
+        if( first )
+        {
+          cairo_new_path( cr );
+        }
+
+        first = false;
+        double x = data[1].point.x;
+        double y = data[1].point.y;
+        transformToArc( parameters, x, y );
+        cairo_move_to( cr, x, y );
+        break;
+      }
+      case CAIRO_PATH_LINE_TO:
+      {
+        double x = data[1].point.x;
+        double y = data[1].point.y;
+        transformToArc( parameters, x, y );
+        cairo_line_to( cr, x, y );
+        break;
+      }
+      case CAIRO_PATH_CURVE_TO:
+      {
+        double x1 = data[1].point.x;
+        double y1 = data[1].point.y;
+        double x2 = data[2].point.x;
+        double y2 = data[2].point.y;
+        double x3 = data[3].point.x;
+        double y3 = data[3].point.y;
+        transformToArc( parameters, x1, y1 );
+        transformToArc( parameters, x2, y2 );
+        transformToArc( parameters, x3, y3 );
+        cairo_curve_to( cr, x1, y1, x2, y2, x3, y3 );
+        break;
+      }
+      case CAIRO_PATH_CLOSE_PATH:
+      {
+        cairo_close_path( cr );
+        break;
+      }
+      default:
+      {
+        DALI_LOG_WARNING( "Type of path not handled.\n" );
+        // Nothing else to do.
+        break;
+      }
+    }
+  }
+}
+
+} // namespace
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+Devel::PixelBuffer RenderTextCairo( const TextAbstraction::TextRenderer::Parameters& parameters )
+{
+  const unsigned int numberOfGlyphs = parameters.glyphs.Count();
+
+  if( 0u == numberOfGlyphs )
+  {
+    // return a pixel buffer with all pixels set to transparent.
+    return CreateVoidPixelBuffer( parameters );
+  }
+
+  // Convert from DALi glyphs to Cairo glyphs.
+  std::vector<cairo_glyph_t> cairoGlyphs;
+  cairoGlyphs.resize( numberOfGlyphs );
+  cairo_glyph_t* cairoGlyphsBuffer = &cairoGlyphs[0u];
+
+  const GlyphInfo* const daliGlyphsBuffer = parameters.glyphs.Begin();
+  const Vector2* const positionsBuffer = parameters.positions.Begin();
+  const ColorIndex* const colorIndicesBuffer = ( 0u == parameters.colorIndices.Count() ) ? nullptr : parameters.colorIndices.Begin();
+
+  for( unsigned index = 0u; index < numberOfGlyphs; ++index )
+  {
+    const GlyphInfo& daliGlyph = *( daliGlyphsBuffer + index );
+    const Vector2& position = *( positionsBuffer + index );
+    cairo_glyph_t& cairoGlyph = *( cairoGlyphsBuffer + index );
+
+    cairoGlyph.index = daliGlyph.index;
+    cairoGlyph.x = std::round( position.x );
+    cairoGlyph.y = std::round( position.y );
+  }
+
+  // Retrieve the FreeType fonts needed by Cairo from the font-client.
+  Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
+
+  FT_Library ftLibrary;
+  FT_Init_FreeType(&ftLibrary);
+
+  // Vector used to store the FreeType font faces, its size and the run of glyphs that use the font.
+  std::vector<GlyphRun> glyphRuns;
+  glyphRuns.reserve( 8u );
+
+  // The size set in Cairo and FreeType has different units.
+  // Before the size is set in Cairo it needs to be converted according the formula
+  // 'pixel_size = point_size * resolution / 72' got from the FreeType doc.
+  // https://www.freetype.org/freetype2/docs/glyphs/glyphs-2.html
+
+  unsigned int horizontalDpi = 0u;
+  unsigned int verticalDpi = 0u;
+  fontClient.GetDpi( horizontalDpi, verticalDpi );
+  const double dVerticalDpi = static_cast<double>( verticalDpi );
+
+  const double FROM_26_DOT_6_TO_PIXELS = dVerticalDpi / ( 64.0 * 72.0 );
+
+  GlyphRun currentGlyphRun;
+  currentGlyphRun.fontId = 0u;
+  currentGlyphRun.colorIndex = 0u;
+  currentGlyphRun.isItalicRequired = false;
+  currentGlyphRun.isBoldRequired = false;
+  for( unsigned index = 0u; index < numberOfGlyphs; ++index )
+  {
+    const GlyphInfo& daliGlyph = *( daliGlyphsBuffer + index );
+    const FontId fontId = daliGlyph.fontId;
+    const ColorIndex colorIndex = ( nullptr == colorIndicesBuffer ) ? 0u : *( colorIndicesBuffer + index );
+    const bool isItalicRequired = daliGlyph.isItalicRequired;
+    const bool isBoldRequired = daliGlyph.isBoldRequired;
+
+    if( ( fontId != currentGlyphRun.fontId ) ||
+        ( ( 0u == fontId ) && ( 0u != daliGlyph.index ) ) ||
+        ( colorIndex != currentGlyphRun.colorIndex ) ||
+        ( isItalicRequired != currentGlyphRun.isItalicRequired ) ||
+        ( isBoldRequired != currentGlyphRun.isBoldRequired ) )
+    {
+      // There is a new run. First set the number of glyphs of the previous run and store it.
+      currentGlyphRun.numberOfGlyphs = index - currentGlyphRun.glyphIndex;
+      if( 0u != currentGlyphRun.numberOfGlyphs )
+      {
+        glyphRuns.push_back( currentGlyphRun );
+      }
+
+      currentGlyphRun.fontFace = nullptr;
+      currentGlyphRun.fontSize = 0.0;
+      currentGlyphRun.glyphIndex = index;
+      currentGlyphRun.numberOfGlyphs = 0u;
+      currentGlyphRun.fontId = 0u;
+      currentGlyphRun.colorIndex = 0u;
+      currentGlyphRun.isItalicRequired = false;
+      currentGlyphRun.isBoldRequired = false;
+
+      if( 0u != fontId )
+      {
+        // Get the font's path file name from the font Id.
+        FontDescription fontDescription;
+        fontClient.GetDescription( fontId, fontDescription );
+
+        switch( fontDescription.type )
+        {
+          case FontDescription::FACE_FONT:
+          {
+            // Create a FreeType font's face.
+            FT_New_Face(ftLibrary, fontDescription.path.c_str(), 0u, &currentGlyphRun.fontFace);
+
+            // Set the font's size. It needs to be set in the Freetype font and in the Cairo's context.
+            unsigned int fontSize = fontClient.GetPointSize( fontId );
+
+            // Font's size to be set in the Cairo's context.
+            currentGlyphRun.fontSize = FROM_26_DOT_6_TO_PIXELS * static_cast<double>( fontSize );
+            break;
+          }
+          case FontDescription::BITMAP_FONT:
+          {
+            //Nothing to do.
+            break;
+          }
+          default:
+          {
+            //Nothing to do.
+            break;
+          }
+        }
+      }
+      currentGlyphRun.fontId = fontId;
+      currentGlyphRun.colorIndex = colorIndex;
+      currentGlyphRun.isItalicRequired = isItalicRequired;
+      currentGlyphRun.isBoldRequired = isBoldRequired;
+    }
+  }
+
+  // Calculate the number of glyphs of the last run and store it.
+  currentGlyphRun.numberOfGlyphs = numberOfGlyphs - currentGlyphRun.glyphIndex;
+  if( 0u != currentGlyphRun.numberOfGlyphs )
+  {
+    glyphRuns.push_back( currentGlyphRun );
+  }
+
+  // Choose the pixel format to be used.
+  //
+  // @note Behdad wrote "Upper 8 bits maps to the fourth byte in a little-endian machine like the intels."
+  //       https://lists.cairographics.org/archives/cairo/2006-March/006563.html
+  //
+  //       Here in practice Cairo's ARGB32 is like DALi's RGBA8888.
+  //
+  const bool isDstRgba = TextAbstraction::TextRenderer::Parameters::RGBA8888 == parameters.pixelFormat;
+  const Pixel::Format pixelFormat = isDstRgba ? Pixel::Format::RGBA8888 : Pixel::Format::A8;
+  const cairo_format_t cairoFormat = isDstRgba ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A8;
+
+  // This function provides a stride value that will respect all alignment requirements of the
+  // accelerated image-rendering code within cairo.
+  const int stride = cairo_format_stride_for_width( cairoFormat,
+                                                    static_cast<int>( parameters.width ) );
+  const int strideWidth = stride / Pixel::GetBytesPerPixel( pixelFormat );
+
+  // Creates the pixel buffer and retrieves the buffer pointer used to create the Cairo's surface.
+  Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New( strideWidth, parameters.height, pixelFormat );
+
+  unsigned char* buffer = pixelBuffer.GetBuffer();
+  const unsigned int bufferSize = stride * parameters.height;
+  memset( buffer, 0, bufferSize );
+
+  std::unique_ptr<cairo_surface_t, void(*)(cairo_surface_t*)> surfacePtr( cairo_image_surface_create_for_data( buffer,
+                                                                                                               cairoFormat,
+                                                                                                               parameters.width,
+                                                                                                               parameters.height,
+                                                                                                               stride ),
+                                                                          cairo_surface_destroy );
+  cairo_surface_t* surface = surfacePtr.get();
+
+  if( ( nullptr == surface ) || ( CAIRO_STATUS_SUCCESS != cairo_surface_status( surface ) ) )
+  {
+    DALI_LOG_ERROR( "Failed to create a cairo's surface\n" );
+
+    return CreateVoidPixelBuffer( parameters );
+  }
+
+  // Whether the text is circular.
+  const bool isCircularText = 0u != parameters.radius;
+
+  // Creates a surface for circular text.
+  //
+  // The reason to create a surface for circular text is that the strategy
+  // followed is to layout the text in a straight horizontal line and apply a
+  // transform to each vertex that forms the geometry of the glyphs to place
+  // and bend the glyphs accordingly to the circular path.
+  //
+  // As the glyphs are laid out first in a straight line they may exceed the
+  // boundaries of the surface in that case cairo ignores them.
+  std::unique_ptr<cairo_surface_t, void(*)(cairo_surface_t*)> circularSurfacePtr( nullptr, cairo_surface_destroy );
+  cairo_surface_t* circularSurface = nullptr;
+  if( isCircularText )
+  {
+    circularSurfacePtr.reset( cairo_surface_create_similar( surface,
+                                                            CAIRO_CONTENT_ALPHA,
+                                                            parameters.circularWidth,
+                                                            parameters.circularHeight ) );
+    circularSurface = circularSurfacePtr.get();
+
+    if( ( nullptr == circularSurface ) || ( CAIRO_STATUS_SUCCESS != cairo_surface_status( circularSurface ) ) )
+    {
+      DALI_LOG_ERROR( "Failed to create a cairo's circular surface\n" );
+
+      return CreateVoidPixelBuffer( parameters );
+    }
+  }
+
+  std::unique_ptr<cairo_t, void(*)(cairo_t*)> crPtr( cairo_create( surface ), cairo_destroy );
+  cairo_t* cr = crPtr.get();
+
+  if( CAIRO_STATUS_SUCCESS != cairo_status( cr ) )
+  {
+    DALI_LOG_ERROR( "Failed to create a cairo context\n" );
+
+    return CreateVoidPixelBuffer( parameters );
+  }
+
+  std::unique_ptr<cairo_t, void(*)(cairo_t*)> circularCrPtr( nullptr, cairo_destroy );
+  cairo_t* circularCr = nullptr;
+
+  if( isCircularText )
+  {
+    circularCrPtr.reset( cairo_create( circularSurface ) );
+    circularCr = circularCrPtr.get();
+
+    if( CAIRO_STATUS_SUCCESS != cairo_status( circularCr ) )
+    {
+      DALI_LOG_ERROR( "Failed to create a cairo context\n" );
+
+      return CreateVoidPixelBuffer( parameters );
+    }
+  }
+
+  CircularTextParameters circularTextParameters;
+
+  // Render the glyphs.
+  if( isCircularText )
+  {
+    // Set the parameters.
+    circularTextParameters.isClockwise = ( TextAbstraction::TextRenderer::Parameters::CLOCKWISE == parameters.circularLayout );
+
+    circularTextParameters.centerX = static_cast<double>( parameters.centerX );
+    circularTextParameters.centerY = static_cast<double>( parameters.centerY );
+    circularTextParameters.radius = static_cast<double>( parameters.radius );
+    circularTextParameters.invRadius = 1.0 / circularTextParameters.radius;
+    circularTextParameters.beginAngle = -parameters.beginAngle + Dali::Math::PI_2;
+  }
+
+  cairo_move_to( cr, 0.0, 0.0 );
+
+  for( const auto& run: glyphRuns )
+  {
+    const bool isEmoji = parameters.isEmoji[run.glyphIndex];
+    if( isEmoji || ( nullptr == run.fontFace ) )
+    {
+      // Retrieve the color for the glyph.
+      const Vector4& color = parameters.colors[run.colorIndex];
+
+      const unsigned int lastGlyphIndex = run.glyphIndex + run.numberOfGlyphs;
+      for( unsigned int index = run.glyphIndex; index < lastGlyphIndex; ++index )
+      {
+        // Whether it's a bitmap font.
+        const bool doBlendWithTextColor = !isEmoji && ( ColorBlendingMode::MULTIPLY == parameters.blendingMode[index] );
+
+        // Check if there is an embedded image or a bitmap font image.
+        const GlyphIndex glyphFontIndex = daliGlyphsBuffer[index].index;
+        if( 0u != glyphFontIndex )
+        {
+          // The embedded image could be A8, RGBA8888 or BGRA8888.
+          //
+          // If the embedded image is RGBA8888 or BGRA8888 then the cairo's buffer is ARGB32. It's needed to convert from RGBA or BGRA to ARGB.
+          // If the embedded image is A8 it's needed to check if the cairo's buffer is A8 or ARGB32 and do the conversion if needed.
+
+          const cairo_glyph_t& glyph = *( cairoGlyphsBuffer + index );
+
+          // Retrieve the image
+          TextAbstraction::FontClient::GlyphBufferData data;
+          std::unique_ptr<GlyphBuffer> glyphBufferPtr( new GlyphBuffer( data, GlyphBuffer::DELETE ) );
+          if( isEmoji )
+          {
+            data.width = parameters.glyphs[run.glyphIndex].width;
+            data.height = parameters.glyphs[run.glyphIndex].height;
+          }
+
+          fontClient.CreateBitmap( run.fontId, glyphFontIndex, false, false, data, 0u );
+
+          if( nullptr == data.buffer )
+          {
+            // nothing else to do if there is no image.
+            continue;
+          }
+
+          // Calculate the position for the circular text.
+          double glyphX = glyph.x;
+          double glyphY = glyph.y;
+
+          if( isCircularText )
+          {
+            // Center of the bitmap.
+            const double halfWidth = 0.5 * static_cast<double>( data.width );
+            const double halfHeight = 0.5 * static_cast<double>( data.height );
+
+            double centerX = glyph.x + halfWidth;
+            double centerY = glyph.y - halfHeight;
+
+            float radians = circularTextParameters.beginAngle + ( circularTextParameters.isClockwise ? -1.f : 1.f ) * ( Dali::Math::PI_2 + circularTextParameters.invRadius * centerX );
+            radians = fmod( radians, TWO_PI );
+            radians += ( radians < 0.f ) ? TWO_PI : 0.f;
+
+            void ( *transformToArc )( const CircularTextParameters&, double&, double& );
+            transformToArc = circularTextParameters.isClockwise ? &TransformToArcClockwise : &TransformToArcAntiClockwise;
+
+            transformToArc( circularTextParameters, centerX, centerY );
+
+            uint8_t* pixelsOut = nullptr;
+            unsigned int widthOut = data.width;
+            unsigned int heightOut = data.height;
+            const unsigned int pixelSize = Pixel::GetBytesPerPixel( data.format );
+
+            Dali::Internal::Platform::RotateByShear( data.buffer,
+                                                     data.width,
+                                                     data.height,
+                                                     pixelSize,
+                                                     radians,
+                                                     pixelsOut,
+                                                     widthOut,
+                                                     heightOut );
+            if( nullptr != pixelsOut )
+            {
+              delete[] data.buffer;
+              data.buffer = pixelsOut;
+              glyphBufferPtr.get()->type = GlyphBuffer::FREE;
+              data.width = widthOut;
+              data.height = heightOut;
+            }
+
+            glyphX = centerX - 0.5 * static_cast<double>( data.width );
+            glyphY = centerY + 0.5 * static_cast<double>( data.height );
+          }
+
+
+          if( ( Pixel::A8 != data.format ) &&
+              ( Pixel::L8 != data.format ) &&
+              ( Pixel::RGBA8888 != data.format ) &&
+              ( Pixel::BGRA8888 != data.format ) )
+          {
+            DALI_LOG_ERROR( " Cairo Renderer: The valid pixel format for embedded items are A8 or RGBA8888\n" );
+            continue;
+          }
+
+          // Check if the item is out of the buffer.
+          if( ( glyphX + static_cast<float>( data.width ) < 0.f ) ||
+              ( glyphX > static_cast<float>( strideWidth ) ) ||
+              ( glyphY < 0.f ) ||
+              ( glyphY - static_cast<float>( data.height ) > static_cast<float>( parameters.height ) ) )
+          {
+            // The embedded item is completely out of the buffer.
+            continue;
+          }
+
+          const bool isSrcA = ( Pixel::A8 == data.format ) || ( Pixel::L8 == data.format );
+          const bool isSrcRgba = Pixel::RGBA8888 == data.format;
+          const bool isSrcBgra = Pixel::BGRA8888 == data.format;
+
+          // 0 -> image and cairo buffer are A8
+          // 1 -> image is A8, cairo buffer is ARGB
+          // 2 -> image is RGBA and cairo buffer is ARGB
+          // 3 -> image is BGRA and cairo buffer is ARGB
+          int rgbaCase = 0;
+          if( isSrcA && isDstRgba )
+          {
+            rgbaCase = 1;
+          }
+          else if( isSrcRgba && isDstRgba )
+          {
+            rgbaCase = 2;
+          }
+          else if( isSrcBgra && isDstRgba )
+          {
+            rgbaCase = 3;
+          }
+          else if( ( isSrcRgba || isSrcBgra ) && !isDstRgba )
+          {
+            DALI_LOG_ERROR( "Cairo Renderer: The embedded image is RGBA or BGRA and the Cairo's buffer has been creates with A8 format!\n" );
+            continue;
+          }
+
+          // Select the cropped source image area to copy into the surface buffer
+          unsigned int glyphUintX = 0u;
+          unsigned int glyphUintY = 0u;
+          unsigned int srcWidth = data.width;
+          unsigned int srcHeight = data.height;
+          unsigned int xSrcIndex = 0u;
+          unsigned int ySrcIndex = 0u;
+          if( glyphX < 0.f )
+          {
+            xSrcIndex = static_cast<unsigned int>( std::abs( glyphX ) );
+            srcWidth -= xSrcIndex;
+          }
+          else
+          {
+            glyphUintX = static_cast<unsigned int>( glyphX );
+          }
+
+          if( glyphUintX + srcWidth > static_cast<unsigned int>( strideWidth ) )
+          {
+            srcWidth -= ( ( glyphUintX + srcWidth ) - strideWidth );
+          }
+
+          if( glyphY - static_cast<float>( srcHeight ) < 0.f )
+          {
+            ySrcIndex = static_cast<unsigned int>( std::abs( glyphY - static_cast<float>( srcHeight ) ) );
+            srcHeight -= ySrcIndex;
+          }
+          else
+          {
+            glyphUintY = static_cast<unsigned int>( glyphY - static_cast<float>( srcHeight ) );
+          }
+
+          if( glyphUintY + srcHeight > parameters.height )
+          {
+            srcHeight -= ( ( glyphUintY + srcHeight ) - parameters.height );
+          }
+
+          // Calculate the source and destination indices.
+          const unsigned int srcPixelSize = Pixel::GetBytesPerPixel( data.format );
+          const unsigned int dstPixelSize = Pixel::GetBytesPerPixel( pixelFormat );
+
+          unsigned int srcIndex = srcPixelSize * ( ySrcIndex * srcWidth + xSrcIndex );
+          unsigned int dstIndex = dstPixelSize * ( glyphUintY * strideWidth + glyphUintX );
+
+          const unsigned int srcWidthOffset = srcPixelSize * ( data.width - srcWidth );
+          const unsigned int dstWidthOffset = dstPixelSize * ( strideWidth - srcWidth );
+
+          // Copy the image to the surface
+          for( unsigned int j = 0; j < srcHeight; ++j )
+          {
+            for( unsigned int i = 0; i < srcWidth; ++i )
+            {
+              switch( rgbaCase )
+              {
+                case 0: // Both the image's buffer and cairo's buffer are A8
+                {
+                  const unsigned char alpha = *( data.buffer + srcIndex );
+                  if( alpha != 0u )
+                  {
+                    // @todo needs a proper blending!
+                    *( buffer + dstIndex ) = alpha;
+                  }
+                  break;
+                }
+                case 1: // The image's buffer is A8 and the cairo's buffer is ARGB
+                {
+                  const unsigned char alpha = *( data.buffer + srcIndex );
+                  if( alpha != 0u )
+                  {
+                    // @todo needs a proper blending!
+                    const float srcAlpha = TO_FLOAT * static_cast<float>( alpha );
+
+                    // Write the RGBA modulated with the given default color.
+                    const float* const colorPtr = color.AsFloat();
+                    *( buffer + dstIndex + 0u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[0u] * srcAlpha );
+                    *( buffer + dstIndex + 1u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[1u] * srcAlpha );
+                    *( buffer + dstIndex + 2u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[2u] * srcAlpha );
+                    *( buffer + dstIndex + 3u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[3u] * srcAlpha );
+                  }
+                  break;
+                }
+                case 2: // The image's buffer is RGBA and the cairo's buffer is ARGB
+                {
+                  const unsigned char alpha = *(data.buffer + srcIndex + 3u);
+                  if( alpha != 0u )
+                  {
+                    if( doBlendWithTextColor )
+                    {
+                      const float* const colorPtr = color.AsFloat();
+
+                      const float srcAlpha = TO_FLOAT * static_cast<float>(alpha) * colorPtr[3u];
+
+                      *(buffer + dstIndex + 0u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 0u) ) * colorPtr[0u] );
+                      *(buffer + dstIndex + 1u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 1u) ) * colorPtr[1u] );
+                      *(buffer + dstIndex + 2u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 2u) ) * colorPtr[2u] );
+
+                      // Write the alpha.
+                      *(buffer + dstIndex + 3u) = static_cast<unsigned char>( TO_UCHAR * srcAlpha );
+                    }
+                    else
+                    {
+                      // @todo needs a proper blending!
+                      // Write the RGB
+                      *(buffer + dstIndex + 0u) = *(data.buffer + srcIndex + 0u);
+                      *(buffer + dstIndex + 1u) = *(data.buffer + srcIndex + 1u);
+                      *(buffer + dstIndex + 2u) = *(data.buffer + srcIndex + 2u);
+
+                      // Write the alpha.
+                      *(buffer + dstIndex + 3u) = *(data.buffer + srcIndex + 3u);
+                    }
+                  }
+                  break;
+                }
+                case 3: // The image's buffer is BGRA and the cairo's buffer is ARGB
+                {
+                  const unsigned char alpha = *(data.buffer + srcIndex + 3u);
+                  if( alpha != 0u )
+                  {
+                    if( doBlendWithTextColor )
+                    {
+                      const float* const colorPtr = color.AsFloat();
+
+                      const float srcAlpha = TO_FLOAT * static_cast<float>(alpha) * colorPtr[3u];
+
+                      *(buffer + dstIndex + 0u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 2u) ) * colorPtr[0u] );
+                      *(buffer + dstIndex + 1u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 1u) ) * colorPtr[1u] );
+                      *(buffer + dstIndex + 2u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 0u) ) * colorPtr[2u] );
+
+                      // Write the alpha.
+                      *(buffer + dstIndex + 3u) = static_cast<unsigned char>( TO_UCHAR * srcAlpha );
+                    }
+                    else
+                    {
+                      // @todo needs a proper blending!
+                      // Write the RGBA
+                      *(buffer + dstIndex + 0u) = *(data.buffer + srcIndex + 2u);
+                      *(buffer + dstIndex + 1u) = *(data.buffer + srcIndex + 1u);
+                      *(buffer + dstIndex + 2u) = *(data.buffer + srcIndex + 0u);
+                      *(buffer + dstIndex + 3u) = *(data.buffer + srcIndex + 3u);
+                    }
+                  }
+                  break;
+                }
+                default:
+                {
+                  DALI_ASSERT_ALWAYS( !"Cairo Renderer: The accepted values for this switch case are: 0, 1, 2!" );
+                }
+              } // switch
+              srcIndex += srcPixelSize;
+              dstIndex += dstPixelSize;
+            } // for width
+            srcIndex += srcWidthOffset;
+            dstIndex += dstWidthOffset;
+          } // for height
+        }
+      }
+    }
+    else
+    {
+      // Sets the color. The color is actually BGRA
+      const Vector4& color = parameters.colors[run.colorIndex];
+
+      cairo_set_source_rgba( cr,
+                             static_cast<double>( color.b ),
+                             static_cast<double>( color.g ),
+                             static_cast<double>( color.r ),
+                             static_cast<double>( color.a ) );
+
+      // Create the Cairo's font from the FreeType font.
+      std::unique_ptr<cairo_font_face_t, void(*)(cairo_font_face_t*)> fontFacePtr( cairo_ft_font_face_create_for_ft_face( run.fontFace, 0 ), cairo_font_face_destroy );
+      cairo_font_face_t* fontFace = fontFacePtr.get();
+
+      static const cairo_user_data_key_t key = { 0 };
+      cairo_status_t status = cairo_font_face_set_user_data( fontFace, &key, run.fontFace, reinterpret_cast<cairo_destroy_func_t>( FT_Done_Face ) );
+      if( status )
+      {
+        cairo_font_face_destroy(fontFace);
+      }
+
+      unsigned int ftSynthesizeFlag = 0u;
+      if( run.isBoldRequired && !( run.fontFace->style_flags & FT_STYLE_FLAG_BOLD ) )
+      {
+        ftSynthesizeFlag |= CAIRO_FT_SYNTHESIZE_BOLD;
+      }
+
+      cairo_ft_font_face_set_synthesize( fontFace, ftSynthesizeFlag );
+
+      cairo_font_face_reference( fontFace );
+
+      const bool synthesizeItalic = ( run.isItalicRequired && !( run.fontFace->style_flags & FT_STYLE_FLAG_ITALIC ) );
+
+      if( CAIRO_STATUS_SUCCESS != cairo_font_face_status( fontFace ) )
+      {
+        DALI_LOG_ERROR( "Failed to load the Freetype Font\n" );
+      }
+
+      // Sets the font.
+      cairo_set_font_face( isCircularText ? circularCr : cr, fontFace );
+
+      // Sets the size
+      cairo_set_font_size( isCircularText ? circularCr : cr, run.fontSize );
+
+      // Render the glyphs.
+      if( isCircularText )
+      {
+        // Create a new path where the text is laid out on a horizontal straight line.
+        cairo_new_path( circularCr );
+        cairo_move_to( circularCr, 0.0, 0.0 );
+
+        cairo_glyph_path( circularCr, ( cairoGlyphsBuffer + run.glyphIndex ), run.numberOfGlyphs );
+        WrapToCircularPath( cr, circularCr, circularTextParameters );
+      }
+      else
+      {
+        if( synthesizeItalic )
+        {
+          // Apply a shear transform to synthesize the italics.
+          // For a reason Cairo may trim some glyphs if the CAIRO_FT_SYNTHESIZE_OBLIQUE flag is used.
+
+          // This is to calculate an offset used to compensate the 'translation' done by the shear transform
+          // as it's done for the whole render buffer.
+          double maxY = 0.0;
+          for( unsigned int index = run.glyphIndex, endIndex = run.glyphIndex + run.numberOfGlyphs; index < endIndex; ++index )
+          {
+            maxY = std::max( maxY, (*( cairoGlyphsBuffer + index )).y );
+          }
+
+          cairo_matrix_t matrix;
+          cairo_matrix_init( &matrix,
+                                                                                  1.0, 0.0,
+                                   -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE, 1.0,
+                             maxY * TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE, 0.0 );
+
+          cairo_transform( cr, &matrix );
+        }
+
+        cairo_show_glyphs( cr, ( cairoGlyphsBuffer + run.glyphIndex ), run.numberOfGlyphs );
+
+        if( synthesizeItalic )
+        {
+          // Restore the transform matrix to the identity.
+          cairo_matrix_t matrix;
+          cairo_matrix_init_identity( &matrix );
+          cairo_set_matrix( cr, &matrix );
+        }
+      }
+      cairo_fill( cr );
+    }
+  }
+
+  return pixelBuffer;
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/internal/text/text-abstraction/cairo-renderer.h b/dali/internal/text/text-abstraction/cairo-renderer.h
new file mode 100755 (executable)
index 0000000..4b6595f
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_CAIRO_RENDERER_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_CAIRO_RENDERER_H
+
+/*
+ * Copyright (c) 2019 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/devel-api/text-abstraction/text-renderer.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+/**
+ * @brief Cairo implementation of the Dali::TextAbstraction::TextRenderer interface.
+ *
+ * @see Dali::TextAbstraction::TextRenderer.
+ */
+Devel::PixelBuffer RenderTextCairo( const TextAbstraction::TextRenderer::Parameters& parameters );
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TEXT_ABSTRACTION_CAIRO_RENDERER_H
+
old mode 100644 (file)
new mode 100755 (executable)
index 3d0f72b..cb9d9fc
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -204,6 +204,16 @@ void FontClient::GetFixedSizes( const FontDescription& fontDescription,
   mPlugin->GetFixedSizes( fontDescription, sizes );
 }
 
+bool FontClient::HasItalicStyle( FontId fontId ) const
+{
+  if( !mPlugin )
+  {
+    return false;
+  }
+
+  return mPlugin->HasItalicStyle( fontId );
+}
+
 FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 requestedPointSize, FaceIndex faceIndex )
 {
   CreatePlugin();
@@ -225,11 +235,18 @@ FontId FontClient::GetFontId( const FontDescription& fontDescription,
                              faceIndex );
 }
 
+FontId FontClient::GetFontId( const BitmapFont& bitmapFont )
+{
+  CreatePlugin();
+
+  return mPlugin->GetFontId( bitmapFont );
+}
+
 void FontClient::GetFontMetrics( FontId fontId, FontMetrics& metrics )
 {
   CreatePlugin();
 
-  return mPlugin->GetFontMetrics( fontId, metrics );
+  mPlugin->GetFontMetrics( fontId, metrics );
 }
 
 GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
@@ -246,11 +263,11 @@ bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType typ
   return mPlugin->GetGlyphMetrics( array, size, type, horizontal );
 }
 
-void FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItalic, bool softwareBold, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+void FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
 {
   CreatePlugin();
 
-  mPlugin->CreateBitmap( fontId, glyphIndex, softwareItalic, softwareBold, data, outlineWidth );
+  mPlugin->CreateBitmap( fontId, glyphIndex, isItalicRequired, isBoldRequired, data, outlineWidth );
 }
 
 PixelData FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
@@ -264,7 +281,7 @@ void FontClient::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorB
 {
   CreatePlugin();
 
-  return mPlugin->CreateVectorBlob( fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
+  mPlugin->CreateVectorBlob( fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
 }
 
 const GlyphInfo& FontClient::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
@@ -281,6 +298,13 @@ bool FontClient::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
   return mPlugin->IsColorGlyph( fontId, glyphIndex );
 }
 
+GlyphIndex FontClient::CreateEmbeddedItem(const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat)
+{
+  CreatePlugin();
+
+  return mPlugin->CreateEmbeddedItem( description, pixelFormat );
+}
+
 FT_FaceRec_* FontClient::GetFreetypeFace( FontId fontId )
 {
   CreatePlugin();
@@ -288,6 +312,13 @@ FT_FaceRec_* FontClient::GetFreetypeFace( FontId fontId )
   return mPlugin->GetFreetypeFace( fontId );
 }
 
+FontDescription::Type FontClient::GetFontType( FontId fontId )
+{
+  CreatePlugin();
+
+  return mPlugin->GetFontType( fontId );
+}
+
 bool FontClient::AddCustomFontDirectory( const FontPath& path )
 {
   CreatePlugin();
old mode 100644 (file)
new mode 100755 (executable)
index 0d9cf71..37596b4
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H
 
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -136,6 +136,11 @@ public:
                     FaceIndex faceIndex );
 
   /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFontId( const BitmapFont& bitmapFont )
+   */
+  FontId GetFontId( const BitmapFont& bitmapFont );
+
+  /**
    * @copydoc Dali::TextAbstraction::FontClient::IsScalable( const FontPath& path )
    */
   bool IsScalable( const FontPath& path );
@@ -157,6 +162,11 @@ public:
                       Dali::Vector< PointSize26Dot6 >& sizes );
 
   /**
+   * @copydoc Dali::TextAbstraction::FontClient::HasItalicStyle()
+   */
+  bool HasItalicStyle( FontId fontId ) const;
+
+  /**
    * @copydoc Dali::TextAbstraction::FontClient::GetFontMetrics()
    */
   void GetFontMetrics( FontId fontId, FontMetrics& metrics );
@@ -172,9 +182,9 @@ public:
   bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal );
 
   /**
-   * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItalic, bool softwareBold, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+   * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
    */
-  void CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItalic, bool softwareBold, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth );
+  void CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth );
 
   /**
    * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
@@ -197,6 +207,11 @@ public:
   bool IsColorGlyph( FontId fontId, GlyphIndex glyphIndex );
 
   /**
+   * @copydoc Dali::TextAbstraction::FontClient::CreateEmbeddedItem()
+   */
+  GlyphIndex CreateEmbeddedItem( const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat );
+
+  /**
    * @brief Retrieves the pointer to the FreeType Font Face for the given @p fontId.
    *
    * @param[in] fontId The font id.
@@ -206,6 +221,15 @@ public:
   FT_FaceRec_* GetFreetypeFace( FontId fontId );
 
   /**
+   * @brief Retrieves the type of font.
+   *
+   * @param[in] fontId The font id.
+   *
+   * @return FACE_FONT if the font has been loaded by FreeType, BITMAP_FONT if it's a font that has been loaded from images or INVALID if it's a non valid font.
+   */
+  FontDescription::Type GetFontType( FontId fontId );
+
+  /**
    * @copydoc Dali::TextAbstraction::FontClient::AddCustomFontDirectory()
    */
   bool AddCustomFontDirectory( const FontPath& path );
old mode 100644 (file)
new mode 100755 (executable)
index 1d157c9..99da7ab
@@ -27,6 +27,7 @@
 #include <dali/internal/text/text-abstraction/font-client-helper.h>
 #include <dali/internal/imaging/common/image-operations.h>
 #include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
 
 // EXTERNAL INCLUDES
 #include <fontconfig/fontconfig.h>
@@ -43,7 +44,6 @@ Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New
  */
 const float FROM_266 = 1.0f / 64.0f;
 const float POINTS_PER_INCH = 72.f;
-const FT_Fixed FONT_SLANT_TANGENT = 0.221694663 * 0x10000; // For support software italic
 
 const std::string FONT_FORMAT( "TrueType" );
 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
@@ -180,9 +180,11 @@ FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
   mFaceIndex( face ),
   mMetrics( metrics ),
   mCharacterSet( nullptr ),
-  mFixedWidthPixels( 0.0f ),
-  mFixedHeightPixels( 0.0f ),
-  mVectorFontId( 0 ),
+  mFixedSizeIndex( 0 ),
+  mFixedWidthPixels( 0.f ),
+  mFixedHeightPixels( 0.f ),
+  mVectorFontId( 0u ),
+  mFontId( 0u ),
   mIsFixedSizeBitmap( false ),
   mHasColorTables( false )
 {
@@ -193,6 +195,7 @@ FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
                                                           PointSize26Dot6 requestedPointSize,
                                                           FaceIndex face,
                                                           const FontMetrics& metrics,
+                                                          int fixedSizeIndex,
                                                           float fixedWidth,
                                                           float fixedHeight,
                                                           bool hasColorTables )
@@ -202,9 +205,11 @@ FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
   mFaceIndex( face ),
   mMetrics( metrics ),
   mCharacterSet( nullptr ),
+  mFixedSizeIndex( fixedSizeIndex ),
   mFixedWidthPixels( fixedWidth ),
   mFixedHeightPixels( fixedHeight ),
-  mVectorFontId( 0 ),
+  mVectorFontId( 0u ),
+  mFontId( 0u ),
   mIsFixedSizeBitmap( true ),
   mHasColorTables( hasColorTables )
 {
@@ -218,6 +223,7 @@ FontClient::Plugin::Plugin( unsigned int horizontalDpi,
   mDefaultFontDescription(),
   mSystemFonts(),
   mDefaultFonts(),
+  mFontIdCache(),
   mFontFaceCache(),
   mValidatedFontCache(),
   mFontDescriptionCache( 1u ),
@@ -225,6 +231,7 @@ FontClient::Plugin::Plugin( unsigned int horizontalDpi,
   mFontDescriptionSizeCache(),
   mVectorFontCache( nullptr ),
   mEllipsisCache(),
+  mEmbeddedItemCache(),
   mDefaultFontDescriptionCached( false )
 {
   mCharacterSetCache.Resize( 1u );
@@ -467,20 +474,44 @@ void FontClient::Plugin::GetDescription( FontId id,
 {
   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n");
   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
+  const FontId index = id - 1u;
 
-  for( const auto& item : mFontDescriptionSizeCache )
+  if( ( id > 0u ) && ( index < mFontIdCache.Count() ) )
   {
-    if( item.fontId == id )
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+    switch( fontIdCacheItem.type )
     {
-      fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
-
-      DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
-      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
-      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
-      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
-      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
-      DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
-      return;
+      case FontDescription::FACE_FONT:
+      {
+        for( const auto& item : mFontDescriptionSizeCache )
+        {
+          if( item.fontId == fontIdCacheItem.id )
+          {
+            fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
+
+            DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
+            DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
+            DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
+            DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
+            DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
+            DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
+            return;
+          }
+        }
+        break;
+      }
+      case FontDescription::BITMAP_FONT:
+      {
+        fontDescription.type = FontDescription::BITMAP_FONT;
+        fontDescription.family = mBitmapFontCache[fontIdCacheItem.id].font.name;
+        break;
+      }
+      default:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+        fontDescription.type = FontDescription::INVALID;
+        fontDescription.family.clear();
+      }
     }
   }
 
@@ -495,11 +526,27 @@ PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
   const FontId index = id - 1u;
 
   if( ( id > 0u ) &&
-      ( index < mFontFaceCache.size() ) )
+      ( index < mFontIdCache.Count() ) )
   {
-    DALI_LOG_INFO( gLogFilter, Debug::General, "  point size : %d\n", ( *( mFontFaceCache.begin() + index ) ).mRequestedPointSize );
-    DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
-    return ( *( mFontFaceCache.begin() + index ) ).mRequestedPointSize;
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+
+    switch( fontIdCacheItem.type )
+    {
+      case FontDescription::FACE_FONT:
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::General, "  point size : %d\n", ( *( mFontFaceCache.begin() + fontIdCacheItem.id ) ).mRequestedPointSize );
+        DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
+        return ( *( mFontFaceCache.begin() + fontIdCacheItem.id ) ).mRequestedPointSize;
+      }
+      case FontDescription::BITMAP_FONT:
+      {
+        return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+      }
+      default:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+      }
+    }
   }
   else
   {
@@ -517,7 +564,7 @@ bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character ch
   DALI_LOG_INFO( gLogFilter, Debug::General, "    font id : %d\n", fontId );
   DALI_LOG_INFO( gLogFilter, Debug::General, "  character : %p\n", character );
 
-  if( ( fontId < 1u ) || ( fontId > mFontFaceCache.size() ) )
+  if( ( fontId < 1u ) || ( fontId > mFontIdCache.Count() ) )
   {
     DALI_LOG_INFO( gLogFilter, Debug::General, "  Invalid font id. Number of items in the cache: %d\n",mFontFaceCache.size());
     DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
@@ -528,35 +575,62 @@ bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character ch
 
   bool isSupported = false;
 
-  FontFaceCacheItem& cacheItem = mFontFaceCache[fontId];
+  const FontIdCacheItem& fontIdCacheItem = mFontIdCache[fontId];
 
-  if( nullptr == cacheItem.mCharacterSet )
+  switch( fontIdCacheItem.type )
   {
-    // Create again the character set.
-    // It can be null if the ResetSystemDefaults() method has been called.
+    case FontDescription::FACE_FONT:
+    {
+      FontFaceCacheItem& cacheItem = mFontFaceCache[fontIdCacheItem.id];
 
-    FontDescription description;
-    description.path = cacheItem.mPath;
-    description.family = std::move( FontFamily( cacheItem.mFreeTypeFace->family_name ) );
-    description.weight = FontWeight::NONE;
-    description.width = FontWidth::NONE;
-    description.slant = FontSlant::NONE;
+      if( nullptr == cacheItem.mCharacterSet )
+      {
+        // Create again the character set.
+        // It can be null if the ResetSystemDefaults() method has been called.
+
+        FontDescription description;
+        description.path = cacheItem.mPath;
+        description.family = std::move( FontFamily( cacheItem.mFreeTypeFace->family_name ) );
+        description.weight = FontWeight::NONE;
+        description.width = FontWidth::NONE;
+        description.slant = FontSlant::NONE;
+
+        // Note FreeType doesn't give too much info to build a proper font style.
+        if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC )
+        {
+          description.slant = FontSlant::ITALIC;
+        }
+        if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD )
+        {
+          description.weight = FontWeight::BOLD;
+        }
 
-    // Note FreeType doesn't give too much info to build a proper font style.
-    if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC )
+        cacheItem.mCharacterSet = CreateCharacterSetFromDescription( description );
+      }
+
+      isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character );
+      break;
+    }
+    case FontDescription::BITMAP_FONT:
     {
-      description.slant = FontSlant::ITALIC;
+      const BitmapFont& bitmapFont = mBitmapFontCache[fontIdCacheItem.id].font;
+
+      for( const auto& glyph : bitmapFont.glyphs )
+      {
+        if( glyph.utf32 == character )
+        {
+          isSupported = true;
+          break;
+        }
+      }
+      break;
     }
-    if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD )
+    default:
     {
-      description.weight = FontWeight::BOLD;
+      DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
     }
-
-    cacheItem.mCharacterSet = CreateCharacterSetFromDescription( description );
   }
 
-  isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character );
-
   DALI_LOG_INFO( gLogFilter, Debug::General, "  is supported : %s\n", (isSupported ? "true" : "false") );
   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
   return isSupported;
@@ -610,9 +684,9 @@ FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
       if( preferColor )
       {
         if( ( fontId > 0 ) &&
-            ( fontId - 1u < mFontFaceCache.size() ) )
+            ( fontId - 1u < mFontIdCache.Count() ) )
         {
-          const FontFaceCacheItem& item = mFontFaceCache[fontId - 1u];
+          const FontFaceCacheItem& item = mFontFaceCache[mFontIdCache[fontId - 1u].id];
 
           foundColor = item.mHasColorTables;
         }
@@ -729,11 +803,11 @@ FontId FontClient::Plugin::GetFontId( const FontPath& path,
   DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
   DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
 
-  FontId id( 0 );
+  FontId id = 0u;
 
   if( nullptr != mFreeTypeLibrary )
   {
-    FontId foundId(0);
+    FontId foundId = 0u;
     if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
     {
       id = foundId;
@@ -763,16 +837,19 @@ FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
   DALI_LOG_INFO( gLogFilter, Debug::General, "   requestedPointSize : %d\n", requestedPointSize );
 
   // This method uses three vectors which caches:
+  // * The bitmap font cache
   // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
   // * The path to font file names.
   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
 
-  // 1) Checks in the cache if the font's description has been validated before.
+  // 1) Checks if the font description matches with a previously loaded bitmap font.
+  //    Returns if a font is found.
+  // 2) Checks in the cache if the font's description has been validated before.
   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
   //    retrieves using font config a path to a font file name which matches with the
   //    font's description. The path is stored in the cache.
   //
-  // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
+  // 3) Checks in the cache if the pair 'font point size, index to the vector with paths to
   //    font file names' exists. If exists, it gets the font id. If it doesn't it calls
   //    the GetFontId() method with the path to the font file name and the point size to
   //    get the font id.
@@ -780,7 +857,13 @@ FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
   // The font id to be returned.
   FontId fontId = 0u;
 
-  // Check first if the font's description have been validated before.
+  // Check first if the font description matches with a previously loaded bitmap font.
+  if( FindBitmapFont( fontDescription.family, fontId ) )
+  {
+    return fontId;
+  }
+
+  // Check if the font's description have been validated before.
   FontDescriptionId validatedFontId = 0u;
 
   if( !FindValidatedFont( fontDescription,
@@ -791,8 +874,9 @@ FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
                   validatedFontId );
   }
 
+  FontId fontFaceId = 0u;
   // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
-  if( !FindFont( validatedFontId, requestedPointSize, fontId ) )
+  if( !FindFont( validatedFontId, requestedPointSize, fontFaceId ) )
   {
     // Retrieve the font file name path.
     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
@@ -803,12 +887,17 @@ FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
                         faceIndex,
                         false );
 
-    mFontFaceCache[fontId-1u].mCharacterSet = mCharacterSetCache[validatedFontId];
+    fontFaceId = mFontIdCache[fontId-1u].id;
+    mFontFaceCache[fontFaceId].mCharacterSet = mCharacterSetCache[validatedFontId];
 
     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
     mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
                                                                        requestedPointSize,
-                                                                       fontId ) );
+                                                                       fontFaceId ) );
+  }
+  else
+  {
+    fontId = mFontFaceCache[fontFaceId].mFontId + 1u;
   }
 
   DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
@@ -817,6 +906,56 @@ FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
   return fontId;
 }
 
+FontId FontClient::Plugin::GetFontId( const BitmapFont& bitmapFont )
+{
+  for( const auto& item : mBitmapFontCache )
+  {
+    if( bitmapFont.name == item.font.name )
+    {
+      return item.id + 1u;
+    }
+  }
+
+  BitmapFontCacheItem bitmapFontCacheItem;
+  bitmapFontCacheItem.font = bitmapFont;
+  bitmapFontCacheItem.id = mFontIdCache.Count();
+
+  // Resize the vector with the pixel buffers.
+  bitmapFontCacheItem.pixelBuffers.resize( bitmapFont.glyphs.size() );
+
+  // Traverse all the glyphs and load the pixel buffer of those with ascender and descender equal to zero.
+  unsigned int index = 0u;
+  for( auto& glyph : bitmapFontCacheItem.font.glyphs )
+  {
+    Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
+
+    if( EqualsZero( glyph.ascender ) && EqualsZero( glyph.descender ) )
+    {
+      // Load the glyph.
+      pixelBuffer = LoadImageFromFile( glyph.url );
+
+      if( pixelBuffer )
+      {
+        glyph.ascender = static_cast<float>(pixelBuffer.GetHeight());
+      }
+    }
+
+    bitmapFontCacheItem.font.ascender = std::max( glyph.ascender, bitmapFontCacheItem.font.ascender );
+    bitmapFontCacheItem.font.descender = std::min( glyph.descender, bitmapFontCacheItem.font.descender );
+
+    ++index;
+  }
+
+  FontIdCacheItem fontIdCacheItem;
+  fontIdCacheItem.type = FontDescription::BITMAP_FONT;
+  fontIdCacheItem.id = mBitmapFontCache.size();
+
+  mBitmapFontCache.push_back( std::move( bitmapFontCacheItem ) );
+  mFontIdCache.PushBack( fontIdCacheItem );
+
+  return bitmapFontCacheItem.id + 1u;
+}
+
 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
                                        FontDescriptionId& validatedFontId )
 {
@@ -849,6 +988,7 @@ void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
     DALI_LOG_INFO( gLogFilter, Debug::General, "  validatedFontId : %d\n", validatedFontId );
 
     // Add the path to the cache.
+    description.type = FontDescription::FACE_FONT;
     mFontDescriptionCache.push_back( description );
     mCharacterSetCache.PushBack( characterSet );
 
@@ -881,27 +1021,53 @@ void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
 void FontClient::Plugin::GetFontMetrics( FontId fontId,
                                          FontMetrics& metrics )
 {
+  const FontId index = fontId - 1u;
+
   if( ( fontId > 0 ) &&
-      ( fontId - 1u < mFontFaceCache.size() ) )
+      ( index < mFontIdCache.Count() ) )
   {
-    const FontFaceCacheItem& font = mFontFaceCache[fontId-1];
-
-    metrics = font.mMetrics;
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
 
-    // Adjust the metrics if the fixed-size font should be down-scaled
-    if( font.mIsFixedSizeBitmap )
+    switch( fontIdCacheItem.type )
     {
-      const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
+      case FontDescription::FACE_FONT:
+      {
+        const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
+
+        metrics = font.mMetrics;
+
+        // Adjust the metrics if the fixed-size font should be down-scaled
+        if( font.mIsFixedSizeBitmap )
+        {
+          const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
 
-      if( desiredFixedSize > 0.f )
+          if( desiredFixedSize > 0.f )
+          {
+            const float scaleFactor = desiredFixedSize / font.mFixedHeightPixels;
+
+            metrics.ascender = metrics.ascender * scaleFactor;
+            metrics.descender = metrics.descender * scaleFactor;
+            metrics.height = metrics.height * scaleFactor;
+            metrics.underlinePosition = metrics.underlinePosition * scaleFactor;
+            metrics.underlineThickness = metrics.underlineThickness * scaleFactor;
+          }
+        }
+        break;
+      }
+      case FontDescription::BITMAP_FONT:
       {
-        const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
+        const BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
 
-        metrics.ascender = floorf( metrics.ascender * scaleFactor );
-        metrics.descender = floorf( metrics.descender * scaleFactor );
-        metrics.height = floorf( metrics.height * scaleFactor );
-        metrics.underlinePosition = floorf( metrics.underlinePosition * scaleFactor );
-        metrics.underlineThickness = floorf( metrics.underlineThickness * scaleFactor );
+        metrics.ascender = bitmapFontCacheItem.font.ascender;
+        metrics.descender = bitmapFontCacheItem.font.descender;
+        metrics.height = metrics.ascender - metrics.descender;
+        metrics.underlinePosition = bitmapFontCacheItem.font.underlinePosition;
+        metrics.underlineThickness = bitmapFontCacheItem.font.underlineThickness;
+        break;
+      }
+      default:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
       }
     }
   }
@@ -914,17 +1080,23 @@ void FontClient::Plugin::GetFontMetrics( FontId fontId,
 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
                                               Character charcode )
 {
-  GlyphIndex index = 0u;
+  GlyphIndex glyphIndex = 0u;
+  const FontId index = fontId - 1u;
 
   if( ( fontId > 0u ) &&
-      ( fontId - 1u < mFontFaceCache.size() ) )
+      ( index < mFontIdCache.Count() ) )
   {
-    FT_Face ftFace = mFontFaceCache[fontId-1u].mFreeTypeFace;
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
 
-    index = FT_Get_Char_Index( ftFace, charcode );
+    if( FontDescription::FACE_FONT == fontIdCacheItem.type )
+    {
+      FT_Face ftFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
+
+      glyphIndex = FT_Get_Char_Index( ftFace, charcode );
+    }
   }
 
-  return index;
+  return glyphIndex;
 }
 
 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
@@ -950,79 +1122,137 @@ bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
   {
     GlyphInfo& glyph = array[i];
 
-    FontId fontId = glyph.fontId;
+    FontId index = glyph.fontId - 1u;
 
-    if( fontId > 0 &&
-        fontId-1 < mFontFaceCache.size() )
+    if( ( glyph.fontId > 0u ) &&
+        ( index < mFontIdCache.Count() ) )
     {
-      const FontFaceCacheItem& font = mFontFaceCache[fontId-1];
+      const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
 
-      FT_Face ftFace = font.mFreeTypeFace;
+      switch( fontIdCacheItem.type )
+      {
+      case FontDescription::FACE_FONT:
+      {
+        const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
+
+        FT_Face ftFace = font.mFreeTypeFace;
 
 #ifdef FREETYPE_BITMAP_SUPPORT
-      // Check to see if we should be loading a Fixed Size bitmap?
-      if ( font.mIsFixedSizeBitmap )
-      {
-        int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
-        if ( FT_Err_Ok == error )
+        // Check to see if we should be loading a Fixed Size bitmap?
+        if( font.mIsFixedSizeBitmap )
         {
-          glyph.width = font.mFixedWidthPixels;
-          glyph.height = font.mFixedHeightPixels;
-          glyph.advance = font.mFixedWidthPixels;
-          glyph.xBearing = 0.0f;
-          glyph.yBearing = font.mFixedHeightPixels;
+          FT_Select_Size( ftFace, font.mFixedSizeIndex ); ///< @todo: needs to be investigated why it's needed to select the size again.
+          int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
+          if ( FT_Err_Ok == error )
+          {
+            glyph.width = font.mFixedWidthPixels;
+            glyph.height = font.mFixedHeightPixels;
+            glyph.advance = font.mFixedWidthPixels;
+            glyph.xBearing = 0.0f;
+            glyph.yBearing = font.mFixedHeightPixels;
 
-          // Adjust the metrics if the fixed-size font should be down-scaled
-          const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
+            // Adjust the metrics if the fixed-size font should be down-scaled
+            const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
 
-          if( desiredFixedSize > 0.f )
-          {
-            const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
+            if( desiredFixedSize > 0.f )
+            {
+              const float scaleFactor = desiredFixedSize / font.mFixedHeightPixels;
 
-            glyph.width = floorf( glyph.width * scaleFactor );
-            glyph.height = floorf( glyph.height * scaleFactor );
-            glyph.advance = floorf( glyph.advance * scaleFactor );
-            glyph.xBearing = floorf( glyph.xBearing * scaleFactor );
-            glyph.yBearing = floorf( glyph.yBearing * scaleFactor );
+              glyph.width = glyph.width * scaleFactor ;
+              glyph.height = glyph.height * scaleFactor;
+              glyph.advance = glyph.advance * scaleFactor;
+              glyph.xBearing = glyph.xBearing * scaleFactor;
+              glyph.yBearing = glyph.yBearing * scaleFactor;
 
-            glyph.scaleFactor = scaleFactor;
+              glyph.scaleFactor = scaleFactor;
+            }
+          }
+          else
+          {
+            DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error );
+            success = false;
           }
         }
         else
-        {
-          DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error );
-          success = false;
-        }
-      }
-      else
 #endif
-      {
-        int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_NO_AUTOHINT );
-
-        if( FT_Err_Ok == error )
         {
-          glyph.width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
-          glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
-          if( horizontal )
+          int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_NO_AUTOHINT );
+
+          if( FT_Err_Ok == error )
           {
-            glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
-            glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
+            glyph.width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
+            glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
+            if( horizontal )
+            {
+              glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
+              glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
+            }
+            else
+            {
+              glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
+              glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
+            }
           }
           else
           {
-            glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
-            glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
+            success = false;
           }
         }
-        else
+        break;
+      }
+      case FontDescription::BITMAP_FONT:
+      {
+        BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
+
+        unsigned int index = 0u;
+        for( auto& item : bitmapFontCacheItem.font.glyphs )
         {
-          success = false;
+          if( item.utf32 == glyph.index )
+          {
+            Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
+            if( !pixelBuffer )
+            {
+              pixelBuffer = LoadImageFromFile( item.url );
+            }
+
+            glyph.width  = static_cast< float >( pixelBuffer.GetWidth() );
+            glyph.height = static_cast< float >( pixelBuffer.GetHeight() );
+            glyph.xBearing = 0.f;
+            glyph.yBearing = glyph.height + item.descender;
+            glyph.advance = glyph.width;
+            glyph.scaleFactor = 1.f;
+            break;
+          }
+          ++index;
         }
+
+        success = true;
+        break;
+      }
+      default:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+      }
       }
     }
     else
     {
-      success = false;
+      // Check if it's an embedded image.
+      if( ( 0u == glyph.fontId ) && ( 0u != glyph.index ) && ( glyph.index <= mEmbeddedItemCache.Count() ) )
+      {
+        const EmbeddedItem& item = mEmbeddedItemCache[glyph.index - 1u];
+
+        glyph.width = static_cast<float>( item.width );
+        glyph.height = static_cast<float>( item.height );
+        glyph.xBearing = 0.f;
+        glyph.yBearing = glyph.height;
+        glyph.advance = glyph.width;
+        glyph.scaleFactor = 1.f;
+      }
+      else
+      {
+        success = false;
+      }
     }
   }
 
@@ -1036,14 +1266,14 @@ bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
   bool success( true );
 
-  for( unsigned int i=0; i<size; ++i )
+  for( unsigned int i = 0u; i < size; ++i )
   {
     FontId fontId = array[i].fontId;
 
-    if( fontId > 0 &&
-        fontId-1 < mFontFaceCache.size() )
+    if( ( fontId > 0u ) &&
+        ( fontId - 1u ) < mFontIdCache.Count() )
     {
-      FontFaceCacheItem& font = mFontFaceCache[fontId-1];
+      FontFaceCacheItem& font = mFontFaceCache[mFontIdCache[fontId - 1u].id];
 
       if( ! font.mVectorFontId )
       {
@@ -1072,99 +1302,177 @@ bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
 #endif
 }
 
-void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItalic, bool softwareBold, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
 {
-  if( ( fontId > 0 ) &&
-      ( fontId - 1u < mFontFaceCache.size() ) )
-  {
-    FT_Face ftFace = mFontFaceCache[fontId - 1u].mFreeTypeFace;
+  const FontId index = fontId - 1u;
 
-    FT_Error error;
+  if( ( fontId > 0u ) &&
+      ( index < mFontIdCache.Count() ) )
+  {
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
 
-#ifdef FREETYPE_BITMAP_SUPPORT
-    // Check to see if this is fixed size bitmap
-    if ( mFontFaceCache[fontId - 1u].mIsFixedSizeBitmap )
-    {
-      error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
-    }
-    else
-#endif
+    switch( fontIdCacheItem.type )
     {
-      error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT );
-    }
-    if( FT_Err_Ok == error )
+    case FontDescription::FACE_FONT:
     {
-      FT_Glyph glyph;
+      // For the software italics.
+      bool isShearRequired = false;
 
-      if( softwareBold )
+      const FontFaceCacheItem& fontFaceCacheItem = mFontFaceCache[fontIdCacheItem.id];
+      FT_Face ftFace = fontFaceCacheItem.mFreeTypeFace;
+
+      FT_Error error;
+
+#ifdef FREETYPE_BITMAP_SUPPORT
+      // Check to see if this is fixed size bitmap
+      if( fontFaceCacheItem.mIsFixedSizeBitmap )
       {
-        FT_GlyphSlot_Embolden(ftFace->glyph);
+        error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
       }
-
-      if( softwareItalic )
+      else
+#endif
       {
-        // FT Matrix uses 16.16 fixed-point format
-        FT_Matrix transform = {0x10000, FONT_SLANT_TANGENT, 0x00000, 0x10000};
-        FT_Outline_Transform(&ftFace->glyph->outline, &transform);
+        error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT );
       }
+      if( FT_Err_Ok == error )
+      {
+        if( isBoldRequired && !( ftFace->style_flags & FT_STYLE_FLAG_BOLD ) )
+        {
+          // Does the software bold.
+          FT_GlyphSlot_Embolden( ftFace->glyph );
+        }
 
-      error = FT_Get_Glyph( ftFace->glyph, &glyph );
+        if( isItalicRequired && !( ftFace->style_flags & FT_STYLE_FLAG_ITALIC ) )
+        {
+          // Will do the software italic.
+          isShearRequired = true;
+        }
 
-      // Convert to bitmap if necessary
-      if ( FT_Err_Ok == error )
-      {
-        if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
+        FT_Glyph glyph;
+        error = FT_Get_Glyph( ftFace->glyph, &glyph );
+
+        // Convert to bitmap if necessary
+        if ( FT_Err_Ok == error )
         {
-          // Check whether we should create a bitmap for the outline
-          if( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 )
+          if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
           {
-            // Set up a stroker
-            FT_Stroker stroker;
-            error = FT_Stroker_New(mFreeTypeLibrary, &stroker );
-
-            if ( FT_Err_Ok == error )
+            // Check whether we should create a bitmap for the outline
+            if( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 )
             {
-              FT_Stroker_Set( stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 );
-              error = FT_Glyph_StrokeBorder( &glyph, stroker, 0, 1 );
+              // Set up a stroker
+              FT_Stroker stroker;
+              error = FT_Stroker_New( mFreeTypeLibrary, &stroker );
 
-              if ( FT_Err_Ok == error )
+              if( FT_Err_Ok == error )
               {
-                FT_Stroker_Done( stroker );
+                FT_Stroker_Set( stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 );
+                error = FT_Glyph_StrokeBorder( &glyph, stroker, 0, 1 );
+
+                if( FT_Err_Ok == error )
+                {
+                  FT_Stroker_Done( stroker );
+                }
+                else
+                {
+                  DALI_LOG_ERROR( "FT_Glyph_StrokeBorder Failed with error: %d\n", error );
+                }
               }
               else
               {
-                DALI_LOG_ERROR( "FT_Glyph_StrokeBorder Failed with error: %d\n", error );
+                DALI_LOG_ERROR( "FT_Stroker_New Failed with error: %d\n", error );
               }
             }
+
+            error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
+            if( FT_Err_Ok == error )
+            {
+              FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph );
+              ConvertBitmap( data, bitmapGlyph->bitmap, isShearRequired );
+            }
             else
             {
-              DALI_LOG_ERROR( "FT_Stroker_New Failed with error: %d\n", error );
+              DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error );
             }
           }
-
-          error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
-          if ( FT_Err_Ok == error )
-          {
-            FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph );
-            ConvertBitmap( data, bitmapGlyph->bitmap );
-          }
           else
           {
-            DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error );
+            ConvertBitmap( data, ftFace->glyph->bitmap, isShearRequired );
           }
+
+          // Created FT_Glyph object must be released with FT_Done_Glyph
+          FT_Done_Glyph( glyph );
         }
-        else
+      }
+      else
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error );
+      }
+      break;
+    }
+    case FontDescription::BITMAP_FONT:
+    {
+      BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
+
+      unsigned int index = 0u;
+      for( auto& item : bitmapFontCacheItem.font.glyphs )
+      {
+        if( item.utf32 == glyphIndex )
         {
-          ConvertBitmap( data, ftFace->glyph->bitmap );
-        }
+          Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
+          if( !pixelBuffer )
+          {
+            pixelBuffer = LoadImageFromFile( item.url );
+          }
 
-        // Created FT_Glyph object must be released with FT_Done_Glyph
-        FT_Done_Glyph( glyph );
+          data.width = pixelBuffer.GetWidth();
+          data.height = pixelBuffer.GetHeight();
+
+          ConvertBitmap( data, data.width, data.height, pixelBuffer.GetBuffer() );
+
+          // Sets the pixel format.
+          data.format = pixelBuffer.GetPixelFormat();
+          break;
+        }
+        ++index;
       }
+      break;
     }
-    else
+    default:
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+    }
+    }
+  }
+  else
+  {
+    if( ( 0u != glyphIndex ) && ( glyphIndex <= mEmbeddedItemCache.Count() ) )
     {
-      DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error );
+      // It's an embedded item.
+      const EmbeddedItem& item = mEmbeddedItemCache[glyphIndex - 1u];
+
+      data.width = item.width;
+      data.height = item.height;
+      if( 0u != item.pixelBufferId )
+      {
+        Devel::PixelBuffer pixelBuffer = mPixelBufferCache[item.pixelBufferId-1u].pixelBuffer;
+        if( pixelBuffer )
+        {
+          ConvertBitmap( data, pixelBuffer.GetWidth(), pixelBuffer.GetHeight(), pixelBuffer.GetBuffer() );
+
+          // Sets the pixel format.
+          data.format = pixelBuffer.GetPixelFormat();
+        }
+      }
+      else
+      {
+        // Creates the output buffer
+        const unsigned int bufferSize = data.width * data.height * 4u;
+        data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
+
+        memset( data.buffer, 0u, bufferSize );
+
+        // Just creates a void buffer. Doesn't matter what pixel format is set as is the application code the responsible of filling it.
+      }
     }
   }
 }
@@ -1189,17 +1497,18 @@ void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex,
   blobLength = 0;
 
 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
-  if( fontId > 0 &&
-      fontId-1 < mFontFaceCache.size() )
+  if( ( fontId > 0u ) &&
+      ( fontId - 1u < mFontIdCache.Count() ) )
   {
-    FontFaceCacheItem& font = mFontFaceCache[fontId-1];
+    const FontId fontFaceId = mFontIdCache[fontId - 1u].id;
+    FontFaceCacheItem& font = mFontFaceCache[fontFaceId];
 
     if( ! font.mVectorFontId )
     {
       font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
     }
 
-    mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
+    mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontFaceId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
   }
 #endif
 }
@@ -1212,7 +1521,7 @@ const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requested
   // First look into the cache if there is an ellipsis glyph for the requested point size.
   for( const auto& item : mEllipsisCache )
   {
-    if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 )
+    if( item.requestedPointSize != requestedPointSize )
     {
       // Use the glyph in the cache.
 
@@ -1236,7 +1545,7 @@ const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requested
                                        false );
 
   // Set the character index to access the glyph inside the font.
-  item.glyph.index = FT_Get_Char_Index( mFontFaceCache[item.glyph.fontId-1].mFreeTypeFace,
+  item.glyph.index = FT_Get_Char_Index( mFontFaceCache[mFontIdCache[item.glyph.fontId-1u].id].mFreeTypeFace,
                                         ELLIPSIS_CHARACTER );
 
   GetBitmapMetrics( &item.glyph, 1u, true );
@@ -1252,17 +1561,37 @@ bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
 {
   FT_Error error = -1;
 
+  const FontId index = fontId - 1u;
+
 #ifdef FREETYPE_BITMAP_SUPPORT
-  if( ( fontId > 0 ) &&
-      ( fontId - 1u < mFontFaceCache.size() ) )
+  if( ( fontId > 0u ) &&
+      ( index < mFontIdCache.Count() ) )
   {
-    const FontFaceCacheItem& item = mFontFaceCache[fontId - 1u];
-    FT_Face ftFace = item.mFreeTypeFace;
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
 
-    // Check to see if this is fixed size bitmap
-    if( item.mHasColorTables )
+    switch( fontIdCacheItem.type )
+    {
+    case FontDescription::FACE_FONT:
+    {
+      const FontFaceCacheItem& item = mFontFaceCache[fontIdCacheItem.id];
+      FT_Face ftFace = item.mFreeTypeFace;
+
+      // Check to see if this is fixed size bitmap
+      if( item.mHasColorTables )
+      {
+        error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
+      }
+      break;
+    }
+    case FontDescription::BITMAP_FONT:
     {
-      error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
+      error = FT_Err_Ok; // Will return true;
+      break;
+    }
+    default:
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+    }
     }
   }
 #endif
@@ -1274,21 +1603,126 @@ FT_FaceRec_* FontClient::Plugin::GetFreetypeFace( FontId fontId )
 {
   FT_Face fontFace = nullptr;
 
+  const FontId index = fontId - 1u;
   if( ( fontId > 0u ) &&
-      ( fontId - 1u < mFontFaceCache.size() ) )
+      ( index < mFontIdCache.Count() ) )
   {
-    fontFace = mFontFaceCache[fontId - 1u].mFreeTypeFace;
-  }
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
 
+    if( FontDescription::FACE_FONT == fontIdCacheItem.type )
+    {
+      fontFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
+    }
+  }
   return fontFace;
 }
 
+FontDescription::Type FontClient::Plugin::GetFontType( FontId fontId )
+{
+  const FontId index = fontId - 1u;
+  if( ( fontId > 0u ) &&
+      ( index < mFontIdCache.Count() ) )
+  {
+    return mFontIdCache[index].type;
+  }
+  return FontDescription::INVALID;
+}
+
 bool FontClient::Plugin::AddCustomFontDirectory( const FontPath& path )
 {
   // NULL as first parameter means the current configuration is used.
   return FcConfigAppFontAddDir( NULL, reinterpret_cast<const FcChar8 *>( path.c_str() ) );
 }
 
+GlyphIndex FontClient::Plugin::CreateEmbeddedItem( const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat )
+{
+  EmbeddedItem embeddedItem;
+
+  embeddedItem.pixelBufferId = 0u;
+  embeddedItem.width = description.width;
+  embeddedItem.height = description.height;
+
+  pixelFormat = Pixel::A8;
+
+  if( !description.url.empty() )
+  {
+    // Check if the url is in the cache.
+    PixelBufferId index = 0u;
+
+    for( const auto& cacheItem : mPixelBufferCache )
+    {
+      ++index;
+      if( cacheItem.url == description.url )
+      {
+        // The url is in the pixel buffer cache.
+        // Set the index +1 to the vector.
+        embeddedItem.pixelBufferId = index;
+        break;
+      }
+    }
+
+    Devel::PixelBuffer pixelBuffer;
+    if( 0u == embeddedItem.pixelBufferId )
+    {
+      // The pixel buffer is not in the cache. Create one and cache it.
+
+      // Load the image from the url.
+      pixelBuffer = LoadImageFromFile( description.url );
+
+      // Create the cache item.
+      PixelBufferCacheItem pixelBufferCacheItem;
+      pixelBufferCacheItem.pixelBuffer = pixelBuffer;
+      pixelBufferCacheItem.url = description.url;
+
+      // Store the cache item in the cache.
+      mPixelBufferCache.push_back( std::move( pixelBufferCacheItem ) );
+
+      // Set the pixel buffer id to the embedded item.
+      embeddedItem.pixelBufferId = mPixelBufferCache.size();
+    }
+    else
+    {
+      // Retrieve the pixel buffer from the cache to set the pixel format.
+      pixelBuffer = mPixelBufferCache[embeddedItem.pixelBufferId-1u].pixelBuffer;
+    }
+
+    if( pixelBuffer )
+    {
+      // Set the size of the embedded item if it has not been set.
+      if( 0u == embeddedItem.width )
+      {
+        embeddedItem.width = static_cast<unsigned int>( pixelBuffer.GetWidth() );
+      }
+
+      if( 0u == embeddedItem.height )
+      {
+        embeddedItem.height = static_cast<unsigned int>( pixelBuffer.GetHeight() );
+      }
+
+      // Set the pixel format.
+      pixelFormat = pixelBuffer.GetPixelFormat();
+    }
+  }
+
+  // Find if the same embeddedItem has already been created.
+  unsigned int index = 0u;
+  for( const auto& item : mEmbeddedItemCache )
+  {
+    ++index;
+    if( ( item.pixelBufferId == embeddedItem.pixelBufferId ) &&
+        ( item.width == embeddedItem.width ) &&
+        ( item.height == embeddedItem.height ) )
+    {
+      return index;
+    }
+  }
+
+  // Cache the embedded item.
+  mEmbeddedItemCache.PushBack( embeddedItem );
+
+  return mEmbeddedItemCache.Count();
+}
+
 void FontClient::Plugin::InitSystemFonts()
 {
   DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
@@ -1530,6 +1964,7 @@ FontId FontClient::Plugin::CreateFont( const FontPath& path,
     const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
     const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
     const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
+    FontId fontFaceId = 0u;
 
     DALI_LOG_INFO( gLogFilter, Debug::General, "            isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
     DALI_LOG_INFO( gLogFilter, Debug::General, "  hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
@@ -1569,8 +2004,8 @@ FontId FontClient::Plugin::CreateFont( const FontPath& path,
       }
       else
       {
-        float fixedWidth  = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].width );
-        float fixedHeight = static_cast< float >( ftFace->available_sizes[ fixedSizeIndex ].height );
+        const float fixedWidth  = static_cast<float>( ftFace->available_sizes[ fixedSizeIndex ].width );
+        const float fixedHeight = static_cast<float>( ftFace->available_sizes[ fixedSizeIndex ].height );
 
         // Indicate that the font is a fixed sized bitmap
         FontMetrics metrics( fixedHeight, // The ascender in pixels.
@@ -1579,8 +2014,26 @@ FontId FontClient::Plugin::CreateFont( const FontPath& path,
                              0.0f,
                              0.0f );
 
-        mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight, hasColorTables ) );
-        id = mFontFaceCache.size();
+        // Create the FreeType font face item to cache.
+        FontFaceCacheItem fontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables );
+
+        // Set the index to the font's id cache.
+        fontFaceCacheItem.mFontId = mFontIdCache.Count();
+
+        // Create the font id item to cache.
+        FontIdCacheItem fontIdCacheItem;
+        fontIdCacheItem.type = FontDescription::FACE_FONT;
+
+        // Set the index to the FreeType font face cache.
+        fontIdCacheItem.id = mFontFaceCache.size();
+        fontFaceId = fontIdCacheItem.id + 1u;
+
+        // Cache the items.
+        mFontFaceCache.push_back( fontFaceCacheItem );
+        mFontIdCache.PushBack( fontIdCacheItem );
+
+        // Set the font id to be returned.
+        id = mFontIdCache.Count();
       }
     }
     else
@@ -1602,8 +2055,26 @@ FontId FontClient::Plugin::CreateFont( const FontPath& path,
                              static_cast< float >( ftFace->underline_position ) * FROM_266,
                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
 
-        mFontFaceCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
-        id = mFontFaceCache.size();
+        // Create the FreeType font face item to cache.
+        FontFaceCacheItem fontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics );
+
+        // Set the index to the font's id cache.
+        fontFaceCacheItem.mFontId = mFontIdCache.Count();
+
+        // Create the font id item to cache.
+        FontIdCacheItem fontIdCacheItem;
+        fontIdCacheItem.type = FontDescription::FACE_FONT;
+
+        // Set the index to the FreeType font face cache.
+        fontIdCacheItem.id = mFontFaceCache.size();
+        fontFaceId = fontIdCacheItem.id + 1u;
+
+        // Cache the items.
+        mFontFaceCache.push_back( fontFaceCacheItem );
+        mFontIdCache.PushBack( fontIdCacheItem );
+
+        // Set the font id to be returned.
+        id = mFontIdCache.Count();
       }
       else
       {
@@ -1611,11 +2082,11 @@ FontId FontClient::Plugin::CreateFont( const FontPath& path,
       }
     }
 
-    if( 0u != id )
+    if( 0u != fontFaceId )
     {
       if( cacheDescription )
       {
-        CacheFontPath( ftFace, id, requestedPointSize, path );
+        CacheFontPath( ftFace, fontFaceId, requestedPointSize, path );
       }
     }
   }
@@ -1630,7 +2101,37 @@ FontId FontClient::Plugin::CreateFont( const FontPath& path,
   return id;
 }
 
-void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
+void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer )
+{
+  // Set the input dimensions.
+  const ImageDimensions inputDimensions( srcWidth, srcHeight );
+
+  // Set the output dimensions.
+  // If the output dimension is not given, the input dimension is set
+  // and won't be downscaling.
+  data.width = ( data.width == 0 ) ? srcWidth : data.width;
+  data.height = ( data.height == 0 ) ? srcHeight : data.height;
+  const ImageDimensions desiredDimensions( data.width, data.height );
+
+  // Creates the output buffer
+  const unsigned int bufferSize = data.width * data.height * 4u;
+  data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
+
+  if( inputDimensions == desiredDimensions )
+  {
+    // There isn't downscaling.
+    memcpy( data.buffer, srcBuffer, bufferSize );
+  }
+  else
+  {
+    Dali::Internal::Platform::LanczosSample4BPP( srcBuffer,
+                                                 inputDimensions,
+                                                 data.buffer,
+                                                 desiredDimensions );
+  }
+}
+
+void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap, bool isShearRequired )
 {
   if( srcBitmap.width*srcBitmap.rows > 0 )
   {
@@ -1640,12 +2141,72 @@ void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBuffer
       {
         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
         {
-          const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
+          uint8_t* pixelsIn = srcBitmap.buffer;
+          unsigned int width = srcBitmap.width;
+          unsigned height = srcBitmap.rows;
+
+          std::unique_ptr<uint8_t, void(*)(void*)> pixelsOutPtr( nullptr, free );
+
+          if( isShearRequired )
+          {
+            /**
+             * Glyphs' bitmaps with no slant retrieved from FreeType:
+             * __________     ____
+             * |XXXXXXXX|     |XX|
+             * |   XX   |     |XX|
+             * |   XX   |     |XX|
+             * |   XX   |     |XX|
+             * |   XX   |     |XX|
+             * |   XX   |     |XX|
+             * ----------     ----
+             *
+             * Expected glyphs' bitmaps with italic slant:
+             * ____________   ______
+             * |  XXXXXXXX|   |  XX|
+             * |     XX   |   |  XX|
+             * |    XX    |   | XX |
+             * |    XX    |   | XX |
+             * |   XX     |   |XX  |
+             * |   XX     |   |XX  |
+             * ------------   ------
+             *
+             * Glyphs' bitmaps with software italic slant retrieved from FreeType:
+             * __________     ______
+             * |XXXXXXXX|     |  XX|
+             * |   XX   |     |  XX|
+             * |  XX    |     | XX |
+             * |  XX    |     | XX |
+             * | XX     |     |XX  |
+             * | XX     |     |XX  |
+             * ----------     ------
+             *
+             * This difference in some bitmaps' width causes an overlap of some glyphs. This is the reason why a shear operation is done here instead of relying on the experimental FT_GlyphSlot_Oblique() implementation.
+             */
+            unsigned int widthOut = 0u;
+            unsigned int heightOut = 0u;
+            uint8_t* pixelsOut = nullptr;
+
+            Dali::Internal::Platform::HorizontalShear( pixelsIn,
+                                                       width,
+                                                       height,
+                                                       1u,
+                                                       -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE,
+                                                       pixelsOut,
+                                                       widthOut,
+                                                       heightOut );
+
+            width = widthOut;
+            height = heightOut;
+            pixelsIn = pixelsOut;
+            pixelsOutPtr.reset( pixelsOut );
+          }
+
+          const unsigned int bufferSize = width * height;
           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
-          data.width = srcBitmap.width;
-          data.height = srcBitmap.rows;
-          data.format = Pixel::L8;
-          memcpy( data.buffer, srcBitmap.buffer, bufferSize );
+          data.width = width;
+          data.height = height;
+          data.format = Pixel::L8; // Sets the pixel format.
+          memcpy( data.buffer, pixelsIn, bufferSize );
         }
         break;
       }
@@ -1655,32 +2216,9 @@ void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBuffer
       {
         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
         {
-          // Set the input dimensions.
-          const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
-
-          // Set the output dimensions.
-          // If the output dimension is not given, the input dimension is set
-          // and won't be downscaling.
-          data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
-          data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
-          const ImageDimensions desiredDimensions( data.width, data.height );
-
-          // Creates the output buffer
-          const unsigned int bufferSize = data.width * data.height * 4u;
-          data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
+          ConvertBitmap( data, srcBitmap.width, srcBitmap.rows, srcBitmap.buffer );
 
-          if( inputDimensions == desiredDimensions )
-          {
-            // There isn't downscaling.
-            memcpy( data.buffer, srcBitmap.buffer, bufferSize );
-          }
-          else
-          {
-            Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
-                                                         inputDimensions,
-                                                         data.buffer,
-                                                         desiredDimensions );
-          }
+          // Sets the pixel format.
           data.format = Pixel::BGRA8888;
         }
         break;
@@ -1708,11 +2246,11 @@ bool FontClient::Plugin::FindFont( const FontPath& path,
   fontId = 0u;
   for( const auto& cacheItem : mFontFaceCache )
   {
-    ++fontId;
     if( cacheItem.mRequestedPointSize == requestedPointSize &&
         cacheItem.mFaceIndex == faceIndex &&
         cacheItem.mPath == path )
     {
+      fontId = cacheItem.mFontId + 1u;
 
       DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
       DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
@@ -1724,7 +2262,6 @@ bool FontClient::Plugin::FindFont( const FontPath& path,
   DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found\n" );
   DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
 
-  fontId = 0u;
   return false;
 }
 
@@ -1826,6 +2363,22 @@ bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
   return false;
 }
 
+bool FontClient::Plugin::FindBitmapFont( const FontFamily& bitmapFont, FontId& fontId ) const
+{
+  fontId = 0u;
+
+  for( const auto& item : mBitmapFontCache )
+  {
+    if( bitmapFont == item.font.name )
+    {
+      fontId = item.id + 1u;
+      return true;
+    }
+  }
+
+  return false;
+}
+
 bool FontClient::Plugin::IsScalable( const FontPath& path )
 {
   bool isScalable = false;
@@ -1925,6 +2478,32 @@ void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
   FcPatternDestroy( fontFamilyPattern );
 }
 
+bool FontClient::Plugin::HasItalicStyle( FontId fontId ) const
+{
+  bool hasItalicStyle = false;
+
+  const FontId index = fontId - 1u;
+
+  if( ( fontId > 0 ) &&
+      ( index < mFontIdCache.Count() ) )
+  {
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+
+    if( FontDescription::FACE_FONT == fontIdCacheItem.type )
+    {
+      const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
+
+      hasItalicStyle = 0u != ( font.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC );
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
+  }
+
+  return hasItalicStyle;
+}
+
 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
 {
   FontDescription description;
@@ -1963,9 +2542,11 @@ void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Do
 
     mMatchedFcPatternCache.PushBack( match );
 
-    mFontFaceCache[id-1u].mCharacterSet = characterSet;
+    const FontId fontFaceId = id - 1u;
+    mFontFaceCache[fontFaceId].mCharacterSet = characterSet;
 
     // Add the path to the cache.
+    description.type = FontDescription::FACE_FONT;
     mFontDescriptionCache.push_back( description );
     mCharacterSetCache.PushBack( characterSet );
 
@@ -1976,7 +2557,7 @@ void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Do
     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
     mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
                                                                        requestedPointSize,
-                                                                       id ) );
+                                                                       fontFaceId ) );
   }
 }
 
old mode 100644 (file)
new mode 100755 (executable)
index 9bbc70c..514b3d8
  */
 
 // INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
 #include <dali/devel-api/text-abstraction/font-metrics.h>
 #include <dali/devel-api/text-abstraction/glyph-info.h>
 #include <dali/internal/text/text-abstraction/font-client-impl.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
 
 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
 #include <dali/internal/text/glyphy/vector-font-cache.h>
@@ -52,9 +54,18 @@ namespace Internal
 {
 
 /**
- *@brief Type used for indices addressing the vector with front descriptions of validated fonts.
+ * @brief Type used for indices addressing the vector with front descriptions of validated fonts.
  */
 typedef uint32_t FontDescriptionId;
+
+/**
+ * @brief Type used for indices addressing the vector with pixel buffers.
+ */
+typedef uint32_t PixelBufferId;
+
+/**
+ * @brief Vector of character sets.
+ */
 typedef Vector<_FcCharSet*> CharacterSetList;
 
 /**
@@ -62,6 +73,12 @@ typedef Vector<_FcCharSet*> CharacterSetList;
  */
 struct FontClient::Plugin
 {
+  struct FontIdCacheItem
+  {
+    FontDescription::Type type; ///< The type of font.
+    FontId                id;   ///< Index to the cache of fonts for the specified type.
+  };
+
   /**
    * @brief Caches an list of fallback fonts for a given font-description
    */
@@ -118,6 +135,7 @@ struct FontClient::Plugin
                        PointSize26Dot6 requestedPointSize,
                        FaceIndex face,
                        const FontMetrics& metrics,
+                       int fixedSizeIndex,
                        float fixedWidth,
                        float fixedHeight,
                        bool hasColorTables );
@@ -128,9 +146,11 @@ struct FontClient::Plugin
     FaceIndex mFaceIndex;                ///< The face index.
     FontMetrics mMetrics;                ///< The font metrics.
     _FcCharSet* mCharacterSet;           ///< Pointer with the range of characters.
-    FT_Short mFixedWidthPixels;          ///< The height in pixels (fixed size bitmaps only)
-    FT_Short mFixedHeightPixels;         ///< The height in pixels (fixed size bitmaps only)
+    int mFixedSizeIndex;                 ///< Index to the fixed size table for the requested size.
+    float mFixedWidthPixels;             ///< The height in pixels (fixed size bitmaps only)
+    float mFixedHeightPixels;            ///< The height in pixels (fixed size bitmaps only)
     unsigned int mVectorFontId;          ///< The ID of the equivalent vector-based font
+    FontId mFontId;                      ///< Index to the vector with the cache of font's ids.
     bool mIsFixedSizeBitmap : 1;         ///< Whether the font has fixed size bitmaps.
     bool mHasColorTables    : 1;         ///< Whether the font has color tables.
   };
@@ -141,6 +161,35 @@ struct FontClient::Plugin
     GlyphInfo glyph;
   };
 
+ /**
+  * @brief Caches pixel buffers.
+  */
+ struct PixelBufferCacheItem
+ {
+   Devel::PixelBuffer pixelBuffer; ///< The pixel buffer loaded from the url.
+   std::string url;                ///< The url.
+ };
+
+  /**
+   * @brief Caches embedded items.
+   */
+ struct EmbeddedItem
+ {
+   PixelBufferId pixelBufferId; ///< Index to the vector of pixel buffers
+   unsigned int width;          ///< The desired width.
+   unsigned int height;         ///< The desired height.
+ };
+
+ /**
+  * @brief Stores a bitmap font and its pixel buffers per glyph.
+  */
+ struct BitmapFontCacheItem
+ {
+   BitmapFont font;                              ///< The bitmap font.
+   std::vector<Devel::PixelBuffer> pixelBuffers; ///< The pixel buffers of the glyphs.
+   FontId id;                                    ///< Index to the vector with the cache of font's ids.
+ };
+
   /**
    * Constructor.
    *
@@ -254,6 +303,11 @@ struct FontClient::Plugin
                     FaceIndex faceIndex );
 
   /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFontId( const BitmapFont& bitmapFont )
+   */
+  FontId GetFontId( const BitmapFont& bitmapFont );
+
+  /**
    * @copydoc Dali::TextAbstraction::FontClient::IsScalable( const FontPath& path )
    */
   bool IsScalable( const FontPath& path );
@@ -275,6 +329,11 @@ struct FontClient::Plugin
                       Dali::Vector< PointSize26Dot6 >& sizes );
 
   /**
+   * @copydoc Dali::TextAbstraction::FontClient::HasItalicStyle()
+   */
+  bool HasItalicStyle( FontId fontId ) const;
+
+  /**
    * @copydoc Dali::TextAbstraction::FontClient::GetFontMetrics()
    */
   void GetFontMetrics( FontId fontId, FontMetrics& metrics );
@@ -300,9 +359,9 @@ struct FontClient::Plugin
   bool GetVectorMetrics( GlyphInfo* array, uint32_t size, bool horizontal );
 
   /**
-   * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItalic, bool softwareBold, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+   * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
    */
-  void CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItalic, bool softwareBold, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth );
+  void CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth );
 
   /**
    * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
@@ -325,11 +384,21 @@ struct FontClient::Plugin
   bool IsColorGlyph( FontId fontId, GlyphIndex glyphIndex );
 
   /**
+   * @copydoc Dali::TextAbstraction::FontClient::CreateEmbeddedItem()
+   */
+  GlyphIndex CreateEmbeddedItem( const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat );
+
+  /**
    * @copydoc Dali::TextAbstraction::Internal::FontClient::GetFreetypeFace()
    */
   FT_FaceRec_* GetFreetypeFace( FontId fontId );
 
   /**
+   * @copydoc Dali::TextAbstraction::Internal::FontClient::GetFontType()
+   */
+  FontDescription::Type GetFontType( FontId fontId );
+
+  /**
    * @copydoc Dali::TextAbstraction::FontClient::AddCustomFontDirectory()
    */
   bool AddCustomFontDirectory( const FontPath& path );
@@ -406,12 +475,23 @@ private:
                      bool cacheDescription );
 
   /**
+   * @brief Copy the color bitmap given in @p srcBuffer to @p data.
+   *
+   * @param[out] data The bitmap data.
+   * @param[in] srcWidth The width of the bitmap.
+   * @param[in] srcHeight The height of the bitmap.
+   * @param[in] srcBuffer The buffer of the bitmap.
+   */
+  void ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer );
+
+  /**
    * @brief Copy the FreeType bitmap to the given buffer.
    *
    * @param[out] data The bitmap data.
    * @param[in] srcBitmap The FreeType bitmap.
+   * @param[in] isShearRequired Whether the bitmap needs a shear transform (for software italics).
    */
-  void ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap );
+  void ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap, bool isShearRequired );
 
   /**
    * @brief Finds in the cache if there is a triplet with the path to the font file name, the font point size and the face index.
@@ -464,6 +544,16 @@ private:
                  FontId& fontId );
 
   /**
+   * @brief Finds in the cache a bitmap font with the @p bitmapFont family name.
+   *
+   * @param[in] bitmapFont The font's family name.
+   * @param[out] fontId The id of the font.
+   *
+   * @return Whether the font has been found.
+   */
+  bool FindBitmapFont( const FontFamily& bitmapFont, FontId& fontId ) const;
+
+  /**
    * @brief Validate a font description.
    *
    * @param[in] fontDescription The font to validate.
@@ -528,6 +618,7 @@ private:
 
   std::vector<FallbackCacheItem> mFallbackCache; ///< Cached fallback font lists.
 
+  Vector<FontIdCacheItem>                   mFontIdCache;
   std::vector<FontFaceCacheItem>            mFontFaceCache;            ///< Caches the FreeType face and font metrics of the triplet 'path to the font file name, font point size and face index'.
   std::vector<FontDescriptionCacheItem>     mValidatedFontCache;       ///< Caches indices to the vector of font descriptions for a given font.
   FontList                                  mFontDescriptionCache;     ///< Caches font descriptions for the validated font.
@@ -537,6 +628,9 @@ private:
   VectorFontCache* mVectorFontCache;            ///< Separate cache for vector data blobs etc.
   Vector<EllipsisItem> mEllipsisCache;          ///< Caches ellipsis glyphs for a particular point size.
   Vector<_FcPattern*>  mMatchedFcPatternCache;  ///< Contain matched FcPattern pointer.
+  std::vector<PixelBufferCacheItem> mPixelBufferCache; ///< Caches the pixel buffer of a url.
+  Vector<EmbeddedItem> mEmbeddedItemCache; ///< Cache embedded items.
+  std::vector<BitmapFontCacheItem> mBitmapFontCache; ///< Stores bitmap fonts.
 
   bool mDefaultFontDescriptionCached : 1; ///< Whether the default font is cached or not
 };
old mode 100644 (file)
new mode 100755 (executable)
index f72475f..2b62286
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
 #include <harfbuzz/hb.h>
 #include <harfbuzz/hb-ft.h>
 
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
+#endif
+
+}
+
 namespace Dali
 {
 
@@ -136,118 +145,158 @@ struct Shaping::Plugin
     mOffset.Clear();
     mFontId = fontId;
 
-    // Reserve some space to avoid reallocations.
-    const Length numberOfGlyphs = static_cast<Length>( 1.3f * static_cast<float>( numberOfCharacters ) );
-    mIndices.Reserve( numberOfGlyphs );
-    mAdvance.Reserve( numberOfGlyphs );
-    mCharacterMap.Reserve( numberOfGlyphs );
-    mOffset.Reserve( 2u * numberOfGlyphs );
-
     TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
     TextAbstraction::Internal::FontClient& fontClientImpl = TextAbstraction::GetImplementation( fontClient );
 
-    // Create a FreeType font's face.
-    FT_Face face;
+    const FontDescription::Type type = fontClientImpl.GetFontType( fontId );
 
-    face = fontClientImpl.GetFreetypeFace( fontId );
-    if( nullptr == face )
+    switch( type )
     {
-      // Nothing to do if the face is null.
-      return 0u;
-    }
+    case FontDescription::FACE_FONT:
+    {
+      // Reserve some space to avoid reallocations.
+      const Length numberOfGlyphs = static_cast<Length>( 1.3f * static_cast<float>( numberOfCharacters ) );
+      mIndices.Reserve( numberOfGlyphs );
+      mAdvance.Reserve( numberOfGlyphs );
+      mCharacterMap.Reserve( numberOfGlyphs );
+      mOffset.Reserve( 2u * numberOfGlyphs );
+
+      // Retrieve a FreeType font's face.
+      FT_Face face = fontClientImpl.GetFreetypeFace( fontId );
+      if( nullptr == face )
+      {
+        // Nothing to do if the face is null.
+        return 0u;
+      }
 
-    /* Get our harfbuzz font struct */
-    hb_font_t* harfBuzzFont;
-    harfBuzzFont = hb_ft_font_create( face, NULL );
+      unsigned int horizontalDpi = 0u;
+      unsigned int verticalDpi = 0u;
+      fontClient.GetDpi( horizontalDpi, verticalDpi );
 
-    /* Create a buffer for harfbuzz to use */
-    hb_buffer_t* harfBuzzBuffer = hb_buffer_create();
+      FT_Set_Char_Size( face,
+          0u,
+          fontClient.GetPointSize( fontId ),
+          horizontalDpi,
+          verticalDpi );
 
-    const bool rtlDirection = IsRightToLeftScript( script );
-    hb_buffer_set_direction( harfBuzzBuffer,
-                             rtlDirection ? HB_DIRECTION_RTL : HB_DIRECTION_LTR ); /* or LTR */
+      /* Get our harfbuzz font struct */
+      hb_font_t* harfBuzzFont;
+      harfBuzzFont = hb_ft_font_create( face, NULL );
 
-    hb_buffer_set_script( harfBuzzBuffer,
-                          SCRIPT_TO_HARFBUZZ[ script ] ); /* see hb-unicode.h */
+      /* Create a buffer for harfbuzz to use */
+      hb_buffer_t* harfBuzzBuffer = hb_buffer_create();
 
+      const bool rtlDirection = IsRightToLeftScript( script );
+      hb_buffer_set_direction( harfBuzzBuffer,
+          rtlDirection ? HB_DIRECTION_RTL : HB_DIRECTION_LTR ); /* or LTR */
 
-    char* currentLocale = setlocale(LC_MESSAGES,NULL);
+      hb_buffer_set_script( harfBuzzBuffer,
+          SCRIPT_TO_HARFBUZZ[ script ] ); /* see hb-unicode.h */
 
-    std::istringstream stringStream( currentLocale );
-    std::string localeString;
-    std::getline(stringStream, localeString, '_');
-    hb_buffer_set_language( harfBuzzBuffer, hb_language_from_string( localeString.c_str(), localeString.size() ) );
 
-    /* Layout the text */
-    hb_buffer_add_utf32( harfBuzzBuffer, text, numberOfCharacters, 0u, numberOfCharacters );
+      char* currentLocale = setlocale(LC_MESSAGES,NULL);
 
-    hb_shape( harfBuzzFont, harfBuzzBuffer, NULL, 0u );
+      std::istringstream stringStream( currentLocale );
+      std::string localeString;
+      std::getline(stringStream, localeString, '_');
+      hb_buffer_set_language( harfBuzzBuffer, hb_language_from_string( localeString.c_str(), localeString.size() ) );
 
-    /* Get glyph data */
-    unsigned int glyphCount;
-    hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( harfBuzzBuffer, &glyphCount );
-    hb_glyph_position_t *glyphPositions = hb_buffer_get_glyph_positions( harfBuzzBuffer, &glyphCount );
-    const GlyphIndex lastGlyphIndex = glyphCount - 1u;
-    for( GlyphIndex i = 0u; i < glyphCount; )
-    {
-      if( rtlDirection )
-      {
-        // If the direction is right to left, Harfbuzz retrieves the glyphs in the visual order.
-        // The glyphs are needed in the logical order to layout the text in lines.
-        // Do not change the order of the glyphs if they belong to the same cluster.
-        GlyphIndex rtlIndex = lastGlyphIndex - i;
+      /* Layout the text */
+      hb_buffer_add_utf32( harfBuzzBuffer, text, numberOfCharacters, 0u, numberOfCharacters );
 
-        unsigned int cluster = glyphInfo[rtlIndex].cluster;
-        unsigned int previousCluster = cluster;
-        Length numberOfGlyphsInCluster = 0u;
+      hb_shape( harfBuzzFont, harfBuzzBuffer, NULL, 0u );
 
-        while( ( cluster == previousCluster ) )
+      /* Get glyph data */
+      unsigned int glyphCount;
+      hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( harfBuzzBuffer, &glyphCount );
+      hb_glyph_position_t *glyphPositions = hb_buffer_get_glyph_positions( harfBuzzBuffer, &glyphCount );
+      const GlyphIndex lastGlyphIndex = glyphCount - 1u;
+      for( GlyphIndex i = 0u; i < glyphCount; )
+      {
+        if( rtlDirection )
         {
-          ++numberOfGlyphsInCluster;
-          previousCluster = cluster;
+          // If the direction is right to left, Harfbuzz retrieves the glyphs in the visual order.
+          // The glyphs are needed in the logical order to layout the text in lines.
+          // Do not change the order of the glyphs if they belong to the same cluster.
+          GlyphIndex rtlIndex = lastGlyphIndex - i;
 
-          if( rtlIndex > 0u )
-          {
-            --rtlIndex;
+          unsigned int cluster = glyphInfo[rtlIndex].cluster;
+          unsigned int previousCluster = cluster;
+          Length numberOfGlyphsInCluster = 0u;
 
-            cluster = glyphInfo[rtlIndex].cluster;
-          }
-          else
+          while( ( cluster == previousCluster ) )
           {
-            break;
+            ++numberOfGlyphsInCluster;
+            previousCluster = cluster;
+
+            if( rtlIndex > 0u )
+            {
+              --rtlIndex;
+
+              cluster = glyphInfo[rtlIndex].cluster;
+            }
+            else
+            {
+              break;
+            }
           }
-        }
 
-        rtlIndex = lastGlyphIndex - ( i + ( numberOfGlyphsInCluster - 1u ) );
+          rtlIndex = lastGlyphIndex - ( i + ( numberOfGlyphsInCluster - 1u ) );
 
-        for( GlyphIndex j = 0u; j < numberOfGlyphsInCluster; ++j )
-        {
-          const GlyphIndex index = rtlIndex + j;
+          for( GlyphIndex j = 0u; j < numberOfGlyphsInCluster; ++j )
+          {
+            const GlyphIndex index = rtlIndex + j;
+
+            mIndices.PushBack( glyphInfo[index].codepoint );
+            mAdvance.PushBack( floor( glyphPositions[index].x_advance * FROM_266 ) );
+            mCharacterMap.PushBack( glyphInfo[index].cluster );
+            mOffset.PushBack( floor( glyphPositions[index].x_offset * FROM_266 ) );
+            mOffset.PushBack( floor( glyphPositions[index].y_offset * FROM_266 ) );
+          }
 
-          mIndices.PushBack( glyphInfo[index].codepoint );
-          mAdvance.PushBack( floor( glyphPositions[index].x_advance * FROM_266 ) );
-          mCharacterMap.PushBack( glyphInfo[index].cluster );
-          mOffset.PushBack( floor( glyphPositions[index].x_offset * FROM_266 ) );
-          mOffset.PushBack( floor( glyphPositions[index].y_offset * FROM_266 ) );
+          i += numberOfGlyphsInCluster;
         }
+        else
+        {
+          mIndices.PushBack( glyphInfo[i].codepoint );
+          mAdvance.PushBack( floor( glyphPositions[i].x_advance * FROM_266 ) );
+          mCharacterMap.PushBack( glyphInfo[i].cluster );
+          mOffset.PushBack( floor( glyphPositions[i].x_offset * FROM_266 ) );
+          mOffset.PushBack( floor( glyphPositions[i].y_offset * FROM_266 ) );
 
-        i += numberOfGlyphsInCluster;
+          ++i;
+        }
       }
-      else
-      {
-        mIndices.PushBack( glyphInfo[i].codepoint );
-        mAdvance.PushBack( floor( glyphPositions[i].x_advance * FROM_266 ) );
-        mCharacterMap.PushBack( glyphInfo[i].cluster );
-        mOffset.PushBack( floor( glyphPositions[i].x_offset * FROM_266 ) );
-        mOffset.PushBack( floor( glyphPositions[i].y_offset * FROM_266 ) );
 
-        ++i;
+      /* Cleanup */
+      hb_buffer_destroy( harfBuzzBuffer );
+      hb_font_destroy( harfBuzzFont );
+      break;
+    }
+    case FontDescription::BITMAP_FONT:
+    {
+      // Reserve some space to avoid reallocations.
+      // The advance and offset tables can be initialized with zeros as it's not needed to get metrics from the bitmaps here.
+      mIndices.Resize( numberOfCharacters );
+      mAdvance.Resize( numberOfCharacters, 0u );
+      mCharacterMap.Reserve( numberOfCharacters );
+      mOffset.Resize( 2u * numberOfCharacters, 0.f );
+
+      // The utf32 character can be used as the glyph's index.
+      std::copy( text, text + numberOfCharacters, mIndices.Begin() );
+
+      // The glyph to character map is 1 to 1.
+      for( unsigned int index = 0u; index < numberOfCharacters; ++index )
+      {
+        mCharacterMap.PushBack( index );
       }
+      break;
+    }
+    default:
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+    }
     }
-
-    /* Cleanup */
-    hb_buffer_destroy( harfBuzzBuffer );
-    hb_font_destroy( harfBuzzFont );
 
     return mIndices.Count();
   }
diff --git a/dali/internal/text/text-abstraction/text-renderer-impl.cpp b/dali/internal/text/text-abstraction/text-renderer-impl.cpp
new file mode 100755 (executable)
index 0000000..449eaa1
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS  HEADER
+#include <dali/internal/text/text-abstraction/text-renderer-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/singleton-service-impl.h>
+#include <dali/internal/text/text-abstraction/cairo-renderer.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+TextRenderer::TextRenderer()
+{
+}
+
+TextRenderer::~TextRenderer()
+{
+}
+
+TextAbstraction::TextRenderer TextRenderer::Get()
+{
+  TextAbstraction::TextRenderer shapingHandle;
+
+  SingletonService service(SingletonService::Get());
+  if (service)
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton(typeid(TextAbstraction::TextRenderer));
+    if (handle)
+    {
+      // If so, downcast the handle
+      TextRenderer* impl = dynamic_cast< Internal::TextRenderer* >(handle.GetObjectPtr());
+      shapingHandle = TextAbstraction::TextRenderer(impl);
+    }
+    else // create and register the object
+    {
+      shapingHandle = TextAbstraction::TextRenderer(new TextRenderer);
+      service.Register(typeid(shapingHandle), shapingHandle);
+    }
+  }
+
+  return shapingHandle;
+}
+
+Devel::PixelBuffer TextRenderer::Render(const TextAbstraction::TextRenderer::Parameters& parameters)
+{
+  return RenderTextCairo(parameters);
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/internal/text/text-abstraction/text-renderer-impl.h b/dali/internal/text/text-abstraction/text-renderer-impl.h
new file mode 100755 (executable)
index 0000000..5133ff4
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_TEXT_RENDERER_IMPL_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_TEXT_RENDERER_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/text-renderer.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation of the TextRenderer
+ */
+class TextRenderer : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  TextRenderer();
+
+  /**
+   * Destructor
+   */
+  ~TextRenderer();
+
+  /**
+   * @copydoc Dali::TextRenderer::Get()
+   */
+  static TextAbstraction::TextRenderer Get();
+
+  /**
+   * @copydoc Dali::TextRenderer::Render()
+   */
+  Devel::PixelBuffer Render(const TextAbstraction::TextRenderer::Parameters& parameters);
+
+private:
+
+  // Undefined copy constructor.
+  TextRenderer(const TextRenderer&);
+
+  // Undefined assignment constructor.
+  TextRenderer& operator=(const TextRenderer&);
+
+}; // class TextRenderer
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+inline static TextAbstraction::Internal::TextRenderer& GetImplementation(TextAbstraction::TextRenderer& textRenderer)
+{
+  DALI_ASSERT_ALWAYS(textRenderer && "textRenderer handle is empty");
+  BaseObject& handle = textRenderer.GetBaseObject();
+  return static_cast<TextAbstraction::Internal::TextRenderer&>(handle);
+}
+
+inline static const TextAbstraction::Internal::TextRenderer& GetImplementation(const TextAbstraction::TextRenderer& textRenderer)
+{
+  DALI_ASSERT_ALWAYS(textRenderer && "textRenderer handle is empty");
+  const BaseObject& handle = textRenderer.GetBaseObject();
+  return static_cast<const TextAbstraction::Internal::TextRenderer&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TEXT_ABSTRACTION_TEXT_RENDERER_IMPL_H
index fc44496..758d052 100644 (file)
@@ -86,6 +86,7 @@ BuildRequires:  pkgconfig(capi-system-info)
 BuildRequires:  pkgconfig(capi-system-sensor)
 
 BuildRequires:  pkgconfig(libcrypto)
+BuildRequires:  pkgconfig(cairo)
 
 %if %{with wayland}