/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
return false;
}
+bool doGlyphHaveStrikethrough(GlyphIndex index,
+ const Vector<StrikethroughGlyphRun>& strikethroughRuns,
+ Vector4& strikethroughColor)
+{
+ for(Vector<StrikethroughGlyphRun>::ConstIterator it = strikethroughRuns.Begin(),
+ endIt = strikethroughRuns.End();
+ it != endIt;
+ ++it)
+ {
+ const StrikethroughGlyphRun& run = *it;
+
+ if((run.glyphRun.glyphIndex <= index) && (index < run.glyphRun.glyphIndex + run.glyphRun.numberOfGlyphs))
+ {
+ if(run.isColorSet)
+ {
+ strikethroughColor = run.color;
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// Helper method to fetch the underline metrics for the specified font glyph
void FetchFontDecorationlinesMetrics(
TextAbstraction::FontClient& fontClient,
/// Draws the specified underline color to the buffer
void DrawUnderline(
- const Vector4& underlineColor,
- const unsigned int bufferWidth,
- const unsigned int bufferHeight,
- GlyphData& glyphData,
- const float baseline,
- const float currentUnderlinePosition,
- const float maxUnderlineThickness,
- const float lineExtentLeft,
- const float lineExtentRight)
+ const Vector4& underlineColor,
+ const unsigned int bufferWidth,
+ const unsigned int bufferHeight,
+ GlyphData& glyphData,
+ const float baseline,
+ const float currentUnderlinePosition,
+ const float maxUnderlineThickness,
+ const float lineExtentLeft,
+ const float lineExtentRight,
+ const Text::Underline::Type underlineType,
+ const float dashedUnderlineWidth,
+ const float dashedUnderlineGap,
+ const LineRun& line)
{
int underlineYOffset = glyphData.verticalOffset + baseline + currentUnderlinePosition;
uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer());
// Do not write out of bounds.
break;
}
+ if(underlineType == Text::Underline::DASHED)
+ {
+ float dashWidth = dashedUnderlineWidth;
+ float dashGap = 0;
- for(unsigned int x = glyphData.horizontalOffset + lineExtentLeft; x <= glyphData.horizontalOffset + lineExtentRight; x++)
+ for(unsigned int x = glyphData.horizontalOffset + lineExtentLeft; x <= glyphData.horizontalOffset + lineExtentRight; x++)
+ {
+ if(x > bufferWidth - 1)
+ {
+ // Do not write out of bounds.
+ break;
+ }
+ if(dashGap == 0 && dashWidth > 0)
+ {
+ WriteColorToPixelBuffer(glyphData, bitmapBuffer, underlineColor, x, y);
+ dashWidth--;
+ }
+ else if(dashGap < dashedUnderlineGap)
+ {
+ dashGap++;
+ }
+ else
+ {
+ //reset
+ dashWidth = dashedUnderlineWidth;
+ dashGap = 0;
+ }
+ }
+ }
+ else
{
- if(x > bufferWidth - 1)
+ for(unsigned int x = glyphData.horizontalOffset + lineExtentLeft; x <= glyphData.horizontalOffset + lineExtentRight; x++)
+ {
+ if(x > bufferWidth - 1)
+ {
+ // Do not write out of bounds.
+ break;
+ }
+ WriteColorToPixelBuffer(glyphData, bitmapBuffer, underlineColor, x, y);
+ }
+ }
+ }
+ if(underlineType == Text::Underline::DOUBLE)
+ {
+ int secondUnderlineYOffset = glyphData.verticalOffset - line.descender - maxUnderlineThickness;
+ for(unsigned int y = secondUnderlineYOffset; y < secondUnderlineYOffset + maxUnderlineThickness; y++)
+ {
+ if(y > bufferHeight - 1)
{
// Do not write out of bounds.
break;
}
-
- WriteColorToPixelBuffer(glyphData, bitmapBuffer, underlineColor, x, y);
+ for(unsigned int x = glyphData.horizontalOffset + lineExtentLeft; x <= glyphData.horizontalOffset + lineExtentRight; x++)
+ {
+ if(x > bufferWidth - 1)
+ {
+ // Do not write out of bounds.
+ break;
+ }
+ WriteColorToPixelBuffer(glyphData, bitmapBuffer, underlineColor, x, y);
+ }
}
}
}
// Whether to use the default color.
const bool useDefaultColor = (NULL == colorsBuffer);
const Vector4& defaultColor = mModel->GetDefaultColor();
+ Vector4 currentStrikethroughColor;
// Create and initialize the pixel buffer.
GlyphData glyphData;
}
}
- const bool underlineEnabled = mModel->IsUnderlineEnabled();
- const Vector4& underlineColor = mModel->GetUnderlineColor();
- const float underlineHeight = mModel->GetUnderlineHeight();
+ const bool underlineEnabled = mModel->IsUnderlineEnabled();
+ const Vector4& underlineColor = mModel->GetUnderlineColor();
+ const float underlineHeight = mModel->GetUnderlineHeight();
+ const Text::Underline::Type underlineType = mModel->GetUnderlineType();
+ const float dashedUnderlineWidth = mModel->GetDashedUnderlineWidth();
+ const float dashedUnderlineGap = mModel->GetDashedUnderlineGap();
const bool strikethroughEnabled = mModel->IsStrikethroughEnabled();
const Vector4& strikethroughColor = mModel->GetStrikethroughColor();
underlineRuns.Resize(numberOfUnderlineRuns);
mModel->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+ // Get the strikethrough runs.
+ const Length numberOfStrikethroughRuns = mModel->GetNumberOfStrikethroughRuns();
+ Vector<StrikethroughGlyphRun> strikethroughRuns;
+ strikethroughRuns.Resize(numberOfStrikethroughRuns);
+ mModel->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
bool thereAreUnderlinedGlyphs = false;
bool strikethroughGlyphsExist = false;
const bool underlineGlyph = underlineEnabled || IsGlyphUnderlined(glyphIndex, underlineRuns);
thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || underlineGlyph;
- strikethroughGlyphsExist = strikethroughGlyphsExist || strikethroughEnabled;
+ currentStrikethroughColor = strikethroughColor;
+ const bool strikethroughGlyph = strikethroughEnabled || doGlyphHaveStrikethrough(glyphIndex, strikethroughRuns, currentStrikethroughColor);
+ strikethroughGlyphsExist = strikethroughGlyphsExist || strikethroughGlyph;
// Are we still using the same fontId as previous
- if((strikethroughEnabled || underlineGlyph) && (glyphInfo->fontId != lastUnderlinedFontId))
+ if((strikethroughGlyph || underlineGlyph) && (glyphInfo->fontId != lastUnderlinedFontId))
{
// We need to fetch fresh font underline metrics
FetchFontDecorationlinesMetrics(fontClient, glyphInfo, currentUnderlinePosition, underlineHeight, currentUnderlineThickness, maxUnderlineThickness, lastUnderlinedFontId, strikethroughHeight, currentStrikethroughThickness, maxStrikethroughThickness);
// Draw the underline from the leftmost glyph to the rightmost glyph
if(thereAreUnderlinedGlyphs && style == Typesetter::STYLE_UNDERLINE)
{
- DrawUnderline(underlineColor, bufferWidth, bufferHeight, glyphData, baseline, currentUnderlinePosition, maxUnderlineThickness, lineExtentLeft, lineExtentRight);
+ DrawUnderline(underlineColor, bufferWidth, bufferHeight, glyphData, baseline, currentUnderlinePosition, maxUnderlineThickness, lineExtentLeft, lineExtentRight, underlineType, dashedUnderlineWidth, dashedUnderlineGap, line);
}
// Draw the background color from the leftmost glyph to the rightmost glyph
return combinedPixelBuffer;
}
+Devel::PixelBuffer Typesetter::ApplyUnderlineMarkupImageBuffer(Devel::PixelBuffer topPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeight, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset)
+{
+ // Underline-tags (this is for Markup case)
+ // Get the underline runs.
+ const Length numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
+ Vector<GlyphRun> underlineRuns;
+ underlineRuns.Resize(numberOfUnderlineRuns);
+ mModel->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+
+ // Iterate on the consecutive underlined glyph run and connect them into one chunk of underlined characters.
+ Vector<GlyphRun>::ConstIterator itGlyphRun = underlineRuns.Begin();
+ Vector<GlyphRun>::ConstIterator endItGlyphRun = underlineRuns.End();
+ GlyphIndex startGlyphIndex, endGlyphIndex;
+
+ //The outer loop to iterate on the separated chunks of underlined glyph runs
+ while(itGlyphRun != endItGlyphRun)
+ {
+ startGlyphIndex = itGlyphRun->glyphIndex;
+ endGlyphIndex = startGlyphIndex;
+ //The inner loop to make a connected underline for the consecutive characters
+ do
+ {
+ endGlyphIndex += itGlyphRun->numberOfGlyphs;
+ itGlyphRun++;
+ } while(itGlyphRun != endItGlyphRun && itGlyphRun->glyphIndex == endGlyphIndex);
+
+ endGlyphIndex--;
+
+ // Create the image buffer for underline
+ Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset, startGlyphIndex, endGlyphIndex);
+ // Combine the two buffers
+ topPixelBuffer = CombineImageBuffer(topPixelBuffer, underlineImageBuffer, bufferWidth, bufferHeight);
+ }
+
+ return topPixelBuffer;
+}
+
+Devel::PixelBuffer Typesetter::ApplyStrikethroughMarkupImageBuffer(Devel::PixelBuffer topPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeight, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset)
+{
+ // strikethrough-tags (this is for Markup case)
+ // Get the strikethrough runs.
+ const Length numberOfStrikethroughRuns = mModel->GetNumberOfStrikethroughRuns();
+ Vector<StrikethroughGlyphRun> strikethroughRuns;
+ strikethroughRuns.Resize(numberOfStrikethroughRuns);
+ mModel->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+ // Iterate on the consecutive strikethrough glyph run and connect them into one chunk of strikethrough characters.
+ Vector<StrikethroughGlyphRun>::ConstIterator itGlyphRun = strikethroughRuns.Begin();
+ Vector<StrikethroughGlyphRun>::ConstIterator endItGlyphRun = strikethroughRuns.End();
+ GlyphIndex startGlyphIndex, endGlyphIndex;
+
+ //The outer loop to iterate on the separated chunks of strikethrough glyph runs
+ while(itGlyphRun != endItGlyphRun)
+ {
+ startGlyphIndex = itGlyphRun->glyphRun.glyphIndex;
+ endGlyphIndex = startGlyphIndex + itGlyphRun->glyphRun.numberOfGlyphs - 1;
+
+ // Create the image buffer for strikethrough
+ Devel::PixelBuffer strikethroughImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_STRIKETHROUGH, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset, startGlyphIndex, endGlyphIndex);
+ // Combine the two buffers
+ topPixelBuffer = CombineImageBuffer(strikethroughImageBuffer, topPixelBuffer, bufferWidth, bufferHeight);
+
+ itGlyphRun++;
+ }
+
+ return topPixelBuffer;
+}
+
Devel::PixelBuffer Typesetter::ApplyMarkupProcessorOnPixelBuffer(Devel::PixelBuffer topPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeight, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset)
{
// Apply the markup-Processor if enabled
const bool markupProcessorEnabled = mModel->IsMarkupProcessorEnabled();
if(markupProcessorEnabled)
{
- // Underline-tags (this is for Markup case)
- // Get the underline runs.
- const Length numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
- Vector<GlyphRun> underlineRuns;
- underlineRuns.Resize(numberOfUnderlineRuns);
- mModel->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
-
- // Iterate on the consecutive underlined glyph run and connect them into one chunk of underlined characters.
- Vector<GlyphRun>::ConstIterator itGlyphRun = underlineRuns.Begin();
- Vector<GlyphRun>::ConstIterator endItGlyphRun = underlineRuns.End();
- GlyphIndex startGlyphIndex, endGlyphIndex;
-
- //The outer loop to iterate on the separated chunks of underlined glyph runs
- while(itGlyphRun != endItGlyphRun)
- {
- startGlyphIndex = itGlyphRun->glyphIndex;
- endGlyphIndex = startGlyphIndex;
- //The inner loop to make a connected underline for the consecutive characters
- do
- {
- endGlyphIndex += itGlyphRun->numberOfGlyphs;
- itGlyphRun++;
- } while(itGlyphRun != endItGlyphRun && itGlyphRun->glyphIndex == endGlyphIndex);
-
- endGlyphIndex--;
+ topPixelBuffer = ApplyUnderlineMarkupImageBuffer(topPixelBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset);
- // Create the image buffer for underline
- Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset, startGlyphIndex, endGlyphIndex);
- // Combine the two buffers
- topPixelBuffer = CombineImageBuffer(topPixelBuffer, underlineImageBuffer, bufferWidth, bufferHeight);
- }
+ topPixelBuffer = ApplyStrikethroughMarkupImageBuffer(topPixelBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, pixelFormat, horizontalOffset, verticalOffset);
}
return topPixelBuffer;