Fix bug when we use bitmap font.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / text-typesetter.cpp
index 826e894..2689ffb 100644 (file)
@@ -26,6 +26,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/line-helper-functions.h>
 #include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
 #include <dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h>
 #include <dali-toolkit/internal/text/rendering/styles/underline-helper-functions.h>
@@ -95,9 +96,9 @@ void TypesetGlyph(GlyphData&           data,
   const int32_t xOffset = data.horizontalOffset + position->x;
 
   // Whether the given glyph is a color one.
-  const bool     isColorGlyph   = data.glyphBitmap.isColorEmoji || data.glyphBitmap.isColorBitmap;
-  const uint32_t glyphPixelSize = Pixel::GetBytesPerPixel(data.glyphBitmap.format);
-  const uint32_t alphaIndex     = glyphPixelSize - 1u;
+  const bool     isColorGlyph    = data.glyphBitmap.isColorEmoji || data.glyphBitmap.isColorBitmap;
+  const uint32_t glyphPixelSize  = Pixel::GetBytesPerPixel(data.glyphBitmap.format);
+  const uint32_t glyphAlphaIndex = glyphPixelSize - 1u;
 
   // Determinate iterator range.
   const int32_t lineIndexRangeMin = std::max(0, -yOffset);
@@ -113,9 +114,9 @@ void TypesetGlyph(GlyphData&           data,
 
   if(Pixel::RGBA8888 == pixelFormat)
   {
-    const bool swapChannelsBR = Pixel::BGRA8888 == data.glyphBitmap.format;
-
     uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(data.bitmapBuffer.GetBuffer());
+    // Skip basic line.
+    bitmapBuffer += (lineIndexRangeMin + yOffset) * static_cast<int32_t>(data.width);
 
     // Fast-cut if style is MASK or OUTLINE. Outline not shown for color glyph.
     // Just overwrite transparent color and return.
@@ -123,17 +124,17 @@ void TypesetGlyph(GlyphData&           data,
     {
       for(int32_t lineIndex = lineIndexRangeMin; lineIndex < lineIndexRangeMax; ++lineIndex)
       {
-        const int32_t yOffsetIndex   = yOffset + lineIndex;
-        const int32_t verticalOffset = yOffsetIndex * data.width;
-
         // We can use memset here.
-        memset(bitmapBuffer + verticalOffset + xOffset + indexRangeMin, 0, (indexRangeMax - indexRangeMin) * sizeof(uint32_t));
+        memset(bitmapBuffer + xOffset + indexRangeMin, 0, (indexRangeMax - indexRangeMin) * sizeof(uint32_t));
+        bitmapBuffer += data.width;
       }
       return;
     }
 
+    const bool swapChannelsBR = Pixel::BGRA8888 == data.glyphBitmap.format;
+
     // Pointer to the color glyph if there is one.
-    const uint32_t* const colorGlyphBuffer = isColorGlyph ? reinterpret_cast<uint32_t*>(data.glyphBitmap.buffer) : NULL;
+    const uint8_t* glyphBuffer = data.glyphBitmap.buffer;
 
     // Precalculate input color's packed result.
     uint32_t packedInputColor       = 0u;
@@ -144,21 +145,20 @@ void TypesetGlyph(GlyphData&           data,
     *(packedInputColorBuffer + 1u) = static_cast<uint8_t>(color->g * 255);
     *(packedInputColorBuffer)      = static_cast<uint8_t>(color->r * 255);
 
+    // Skip basic line of glyph.
+    glyphBuffer += (lineIndexRangeMin) * static_cast<int32_t>(data.glyphBitmap.width) * glyphPixelSize;
+
     // Traverse the pixels of the glyph line per line.
-    for(int32_t lineIndex = lineIndexRangeMin; lineIndex < lineIndexRangeMax; ++lineIndex)
+    if(isColorGlyph)
     {
-      const int32_t yOffsetIndex = yOffset + lineIndex;
-
-      const int32_t verticalOffset    = yOffsetIndex * data.width;
-      const int32_t glyphBufferOffset = lineIndex * static_cast<int32_t>(data.glyphBitmap.width);
-      for(int32_t index = indexRangeMin; index < indexRangeMax; ++index)
+      for(int32_t lineIndex = lineIndexRangeMin; lineIndex < lineIndexRangeMax; ++lineIndex)
       {
-        const int32_t xOffsetIndex = xOffset + index;
-
-        if(isColorGlyph)
+        for(int32_t index = indexRangeMin; index < indexRangeMax; ++index)
         {
+          const int32_t xOffsetIndex = xOffset + index;
+
           // Retrieves the color from the color glyph.
-          uint32_t packedColorGlyph       = *(colorGlyphBuffer + glyphBufferOffset + index);
+          uint32_t packedColorGlyph       = *(reinterpret_cast<const uint32_t*>(glyphBuffer + (index << 2)));
           uint8_t* packedColorGlyphBuffer = reinterpret_cast<uint8_t*>(&packedColorGlyph);
 
           // Update the alpha channel.
@@ -192,23 +192,28 @@ void TypesetGlyph(GlyphData&           data,
           }
 
           // Set the color into the final pixel buffer.
-          *(bitmapBuffer + verticalOffset + xOffsetIndex) = packedColorGlyph;
+          *(bitmapBuffer + xOffsetIndex) = packedColorGlyph;
         }
-        else
+        bitmapBuffer += data.width;
+        glyphBuffer += data.glyphBitmap.width * glyphPixelSize;
+      }
+    }
+    else
+    {
+      for(int32_t lineIndex = lineIndexRangeMin; lineIndex < lineIndexRangeMax; ++lineIndex)
+      {
+        for(int32_t index = indexRangeMin; index < indexRangeMax; ++index)
         {
-          // Pack the given color into a 32bit buffer. The alpha channel will be updated later for each pixel.
-          // The format is RGBA8888.
-          uint32_t packedColor       = 0u;
-          uint8_t* packedColorBuffer = reinterpret_cast<uint8_t*>(&packedColor);
-
           // Update the alpha channel.
-          const uint8_t alpha = *(data.glyphBitmap.buffer + glyphPixelSize * (glyphBufferOffset + index) + alphaIndex);
+          const uint8_t alpha = *(glyphBuffer + index * glyphPixelSize + glyphAlphaIndex);
 
           // Copy non-transparent pixels only
           if(alpha > 0u)
           {
+            const int32_t xOffsetIndex = xOffset + index;
+
             // Check alpha of overlapped pixels
-            uint32_t& currentColor             = *(bitmapBuffer + verticalOffset + xOffsetIndex);
+            uint32_t& currentColor             = *(bitmapBuffer + xOffsetIndex);
             uint8_t*  packedCurrentColorBuffer = reinterpret_cast<uint8_t*>(&currentColor);
 
             // For any pixel overlapped with the pixel in previous glyphs, make sure we don't
@@ -224,6 +229,11 @@ void TypesetGlyph(GlyphData&           data,
             }
             else
             {
+              // Pack the given color into a 32bit buffer. The alpha channel will be updated later for each pixel.
+              // The format is RGBA8888.
+              uint32_t packedColor       = 0u;
+              uint8_t* packedColorBuffer = reinterpret_cast<uint8_t*>(&packedColor);
+
               // Color is pre-muliplied with its alpha.
               *(packedColorBuffer + 3u) = MultiplyAndNormalizeColor(*(packedInputColorBuffer + 3u), currentAlpha);
               *(packedColorBuffer + 2u) = MultiplyAndNormalizeColor(*(packedInputColorBuffer + 2u), currentAlpha);
@@ -235,35 +245,38 @@ void TypesetGlyph(GlyphData&           data,
             }
           }
         }
+        bitmapBuffer += data.width;
+        glyphBuffer += data.glyphBitmap.width * glyphPixelSize;
       }
     }
   }
-  else
+  else // Pixel::L8
   {
     // Below codes required only if not color glyph.
     if(!isColorGlyph)
     {
-      uint8_t* bitmapBuffer = reinterpret_cast<uint8_t*>(data.bitmapBuffer.GetBuffer());
+      uint8_t*       bitmapBuffer = data.bitmapBuffer.GetBuffer();
+      const uint8_t* glyphBuffer  = data.glyphBitmap.buffer;
+
+      // Skip basic line.
+      bitmapBuffer += (lineIndexRangeMin + yOffset) * static_cast<int32_t>(data.width);
+      glyphBuffer += (lineIndexRangeMin) * static_cast<int32_t>(data.glyphBitmap.width) * glyphPixelSize;
 
       // Traverse the pixels of the glyph line per line.
       for(int32_t lineIndex = lineIndexRangeMin; lineIndex < lineIndexRangeMax; ++lineIndex)
       {
-        const int32_t yOffsetIndex = yOffset + lineIndex;
-
-        const int32_t verticalOffset    = yOffsetIndex * data.width;
-        const int32_t glyphBufferOffset = lineIndex * static_cast<int32_t>(data.glyphBitmap.width);
         for(int32_t index = indexRangeMin; index < indexRangeMax; ++index)
         {
           const int32_t xOffsetIndex = xOffset + index;
 
           // Update the alpha channel.
-          const uint8_t alpha = *(data.glyphBitmap.buffer + glyphPixelSize * (glyphBufferOffset + index) + alphaIndex);
+          const uint8_t alpha = *(glyphBuffer + index * glyphPixelSize + glyphAlphaIndex);
 
           // Copy non-transparent pixels only
           if(alpha > 0u)
           {
             // Check alpha of overlapped pixels
-            uint8_t& currentAlpha = *(bitmapBuffer + verticalOffset + xOffsetIndex);
+            uint8_t& currentAlpha = *(bitmapBuffer + xOffsetIndex);
 
             // For any pixel overlapped with the pixel in previous glyphs, make sure we don't
             // overwrite a previous bigger alpha with a smaller alpha (in order to avoid
@@ -272,6 +285,9 @@ void TypesetGlyph(GlyphData&           data,
             currentAlpha = std::max(currentAlpha, alpha);
           }
         }
+
+        bitmapBuffer += data.width;
+        glyphBuffer += data.glyphBitmap.width * glyphPixelSize;
       }
     }
   }
@@ -486,6 +502,8 @@ Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuff
   const Vector4* const    backgroundColorsBuffer       = model->GetBackgroundColors();
   const ColorIndex* const backgroundColorIndicesBuffer = model->GetBackgroundColorIndices();
 
+  const DevelText::VerticalLineAlignment::Type verLineAlign = model->GetVerticalLineAlignment();
+
   // Create and initialize the pixel buffer.
   GlyphData glyphData;
   glyphData.verticalOffset   = verticalOffset;
@@ -507,13 +525,7 @@ Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuff
     glyphData.horizontalOffset += horizontalOffset;
 
     // Increases the vertical offset with the line's ascender.
-    glyphData.verticalOffset += static_cast<int32_t>(line.ascender);
-
-    // Include line spacing after first line
-    if(lineIndex > 0u)
-    {
-      glyphData.verticalOffset += static_cast<int32_t>(line.lineSpacing);
-    }
+    glyphData.verticalOffset += static_cast<int32_t>(line.ascender + GetPreOffsetVerticalLineAlignment(line, verLineAlign));
 
     float left     = bufferWidth;
     float right    = 0.0f;
@@ -579,7 +591,7 @@ Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuff
     }
 
     // Increases the vertical offset with the line's descender.
-    glyphData.verticalOffset += static_cast<int32_t>(-line.descender);
+    glyphData.verticalOffset += static_cast<int32_t>(-line.descender + GetPostOffsetVerticalLineAlignment(line, verLineAlign));
   }
 
   return glyphData.bitmapBuffer;
@@ -856,29 +868,6 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
     }
   }
 
-  // Calculate vertical line alignment
-  switch(mModel->GetVerticalLineAlignment())
-  {
-    case DevelText::VerticalLineAlignment::TOP:
-    {
-      break;
-    }
-    case DevelText::VerticalLineAlignment::MIDDLE:
-    {
-      const auto& line = *mModel->GetLines();
-      penY -= line.descender;
-      penY += static_cast<int32_t>(line.lineSpacing * 0.5f + line.descender);
-      break;
-    }
-    case DevelText::VerticalLineAlignment::BOTTOM:
-    {
-      const auto& line       = *mModel->GetLines();
-      const auto  lineHeight = line.ascender + (-line.descender) + line.lineSpacing;
-      penY += static_cast<int32_t>(lineHeight - (line.ascender - line.descender));
-      break;
-    }
-  }
-
   // Generate the image buffers of the text for each different style first,
   // then combine all of them together as one final image buffer. We try to
   // do all of these in CPU only, so that once the final texture is generated,
@@ -1046,6 +1035,8 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, co
   const Vector<CharacterIndex>& glyphToCharacterMap       = mModel->GetGlyphsToCharacters();
   const CharacterIndex*         glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
 
+  const DevelText::VerticalLineAlignment::Type verLineAlign = mModel->GetVerticalLineAlignment();
+
   // Traverses the lines of the text.
   for(LineIndex lineIndex = 0u; lineIndex < modelNumberOfLines; ++lineIndex)
   {
@@ -1056,7 +1047,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, co
     glyphData.horizontalOffset += horizontalOffset;
 
     // Increases the vertical offset with the line's ascender.
-    glyphData.verticalOffset += static_cast<int32_t>(line.ascender);
+    glyphData.verticalOffset += static_cast<int32_t>(line.ascender + GetPreOffsetVerticalLineAlignment(line, verLineAlign));
 
     // Retrieves the glyph's outline width
     float outlineWidth = static_cast<float>(mModel->GetOutlineWidth());
@@ -1357,7 +1348,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const uint32_t& bufferWidth, co
     }
 
     // Increases the vertical offset with the line's descender & line spacing.
-    glyphData.verticalOffset += static_cast<int32_t>(-line.descender + line.lineSpacing);
+    glyphData.verticalOffset += static_cast<int32_t>(-line.descender + GetPostOffsetVerticalLineAlignment(line, verLineAlign));
   }
 
   return glyphData.bitmapBuffer;