#include <dali-toolkit/internal/text/character-set-conversion.h>
#include <dali-toolkit/internal/text/color-segmentation.h>
#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/hyphenator.h>
#include <dali-toolkit/internal/text/multi-language-support.h>
#include <dali-toolkit/internal/text/segmentation.h>
#include <dali-toolkit/internal/text/shaper.h>
#include <dali-toolkit/internal/text/text-control-interface.h>
#include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
#include <dali-toolkit/internal/text/text-run-container.h>
#include <dali-toolkit/internal/text/text-selection-handle-controller.h>
Vector<unsigned short> mIndices; ///< container of indices
};
+// The relative luminance of a color is defined as (L = 0.2126 * R + 0.7152 * G + 0.0722 * B)
+// based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
+const float BRIGHTNESS_THRESHOLD = 0.179f;
+const float CONSTANT_R = 0.2126f;
+const float CONSTANT_G = 0.7152f;
+const float CONSTANT_B = 0.0722f;
+const Dali::Vector4 BLACK(0.f, 0.f, 0.f, 1.f);
+const Dali::Vector4 WHITE(1.f, 1.f, 1.f, 1.f);
const Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
const Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
const Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
Vector<Character> displayCharacters;
bool useHiddenText = false;
- if(mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
+ if(mHiddenInput && mEventData != nullptr && !mEventData->mIsShowingPlaceholderText)
{
mHiddenInput->Substitute(srcCharacters, displayCharacters);
useHiddenText = true;
requestedNumberOfCharacters,
lineBreakInfo);
+ if(mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+ mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
+ {
+ CharacterIndex end = startIndex + requestedNumberOfCharacters;
+ LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+
+ for(CharacterIndex index = startIndex; index < end; index++)
+ {
+ CharacterIndex wordEnd = index;
+ while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
+ {
+ wordEnd++;
+ }
+
+ if((wordEnd + 1) == end) // add last char
+ {
+ wordEnd++;
+ }
+
+ Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
+
+ for(CharacterIndex i = 0; i < (wordEnd - index); i++)
+ {
+ if(hyphens[i])
+ {
+ *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
+ }
+ }
+
+ index = wordEnd;
+ }
+ }
+
// Create the paragraph info.
mModel->mLogicalModel->CreateParagraphInfo(startIndex,
requestedNumberOfCharacters);
TextAbstraction::FontDescription defaultFontDescription;
TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale;
- if(IsShowingPlaceholderText() && mEventData && (NULL != mEventData->mPlaceholderFont))
+ //Get the number of points per one unit of point-size
+ uint32_t numberOfPointsPerOneUnitOfPointSize = mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
+
+ if(IsShowingPlaceholderText() && mEventData && (nullptr != mEventData->mPlaceholderFont))
{
// If the placeholder font is set specifically, only placeholder font is changed.
defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
if(mEventData->mPlaceholderFont->sizeDefined)
{
- defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * mFontSizeScale * 64u;
+ defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
}
}
- else if(NULL != mFontDefaults)
+ else if(nullptr != mFontDefaults)
{
// Set the normal font and the placeholder font.
defaultFontDescription = mFontDefaults->mFontDescription;
if(mTextFitEnabled)
{
- defaultPointSize = mFontDefaults->mFitPointSize * 64u;
+ defaultPointSize = mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
}
else
{
- defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * 64u;
+ defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
}
}
// Create the 'number of glyphs' per character and the glyph to character conversion tables.
mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
+
updated = true;
}
updated = true;
}
- if((NULL != mEventData) &&
+ if((nullptr != mEventData) &&
mEventData->mPreEditFlag &&
(0u != mModel->mVisualModel->mCharactersToGlyph.Count()))
{
underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
underlineRun.numberOfGlyphs = numberOfIndices;
mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(false);
+ }
break;
}
case Dali::InputMethodContext::PreeditStyle::REVERSE:
backgroundColorRun.color = textColor;
mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
- Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
+ Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
+ if(backgroundColor.a == 0) // There is no text background color.
+ {
+ // Try use the control's background color.
+ if(nullptr != mEditableControlInterface)
+ {
+ mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
+ if(backgroundColor.a == 0) // There is no control background color.
+ {
+ // Determines black or white color according to text color.
+ // Based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
+ float L = CONSTANT_R * textColor.r + CONSTANT_G * textColor.g + CONSTANT_B * textColor.b;
+ backgroundColor = L > BRIGHTNESS_THRESHOLD ? BLACK : WHITE;
+ }
+ }
+ }
+
Vector<ColorRun> colorRuns;
colorRuns.Resize(1u);
ColorRun& colorRun = *(colorRuns.Begin());
colorRun.color = backgroundColor;
colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
colorRun.characterRun.numberOfCharacters = numberOfIndices;
-
mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
+
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(false);
+ }
break;
}
case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
backgroundColorRun.color = LIGHT_BLUE;
mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
+
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(false);
+ }
break;
}
case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
underlineRun.numberOfGlyphs = numberOfIndices;
mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(false);
+ }
break;
}
case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
underlineRun.numberOfGlyphs = numberOfIndices;
mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(false);
+ }
break;
}
case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
underlineRun.numberOfGlyphs = numberOfIndices;
mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(false);
+ }
break;
}
case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
underlineRun.numberOfGlyphs = numberOfIndices;
mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
+
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(false);
+ }
break;
}
case Dali::InputMethodContext::PreeditStyle::NONE:
updated = true;
}
+ if((NO_OPERATION != (SHAPE_TEXT & operations)) &&
+ !((nullptr != mEventData) &&
+ mEventData->mPreEditFlag &&
+ (0u != mModel->mVisualModel->mCharactersToGlyph.Count())))
+ {
+ //Mark-up processor case
+ if(mModel->mVisualModel->IsMarkupProcessorEnabled())
+ {
+ CopyUnderlinedFromLogicalToVisualModels(true);
+ }
+
+ updated = true;
+ }
+
// The estimated number of lines. Used to avoid reallocations when layouting.
mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
float Controller::Impl::GetDefaultFontLineHeight()
{
FontId defaultFontId = 0u;
- if(NULL == mFontDefaults)
+ if(nullptr == mFontDefaults)
{
TextAbstraction::FontDescription fontDescription;
defaultFontId = mFontClient.GetFontId(fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale);
void Controller::Impl::ChangeState(EventData::State newState)
{
- if(NULL == mEventData)
+ if(nullptr == mEventData)
{
// Nothing to do if there is no text input.
return;
CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) const
{
- if(NULL == mEventData)
+ if(nullptr == mEventData)
{
// Nothing to do if there is no text input.
return 0u;
void Controller::Impl::UpdateCursorPosition(const CursorInfo& cursorInfo)
{
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this);
- if(NULL == mEventData)
+ if(nullptr == mEventData)
{
// Nothing to do if there is no text input.
DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n");
void Controller::Impl::RequestRelayout()
{
- if(NULL != mControlInterface)
+ if(nullptr != mControlInterface)
{
mControlInterface->RequestTextRelayout();
}
Actor Controller::Impl::CreateBackgroundActor()
{
- // NOTE: Currently we only support background color for one line left-to-right text,
- // so the following calculation is based on one line left-to-right text only!
+ // NOTE: Currently we only support background color for left-to-right text.
Actor actor;
const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
const Vector4& defaultBackgroundColor = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
- Vector4 quad;
- uint32_t numberOfQuads = 0u;
+ Vector4 quad;
+ uint32_t numberOfQuads = 0u;
+ Length yLineOffset = 0;
+ Length prevLineIndex = 0;
+ LineIndex lineIndex;
+ Length numberOfLines;
for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
{
const ColorIndex backgroundColorIndex = (nullptr == backgroundColorsBuffer) ? 0u : *(backgroundColorIndicesBuffer + i);
const Vector4& backgroundColor = (0u == backgroundColorIndex) ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
+ mModel->mVisualModel->GetNumberOfLines(i, 1, lineIndex, numberOfLines);
+ Length lineHeight = lineRun[lineIndex].ascender + -(lineRun[lineIndex].descender) + lineRun[lineIndex].lineSpacing;
+
+ if(lineIndex != prevLineIndex)
+ {
+ yLineOffset += lineHeight;
+ }
+
// Only create quads for glyphs with a background color
if(backgroundColor != Color::TRANSPARENT)
{
if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
{
quad.x = position.x;
- quad.y = 0.0f;
+ quad.y = yLineOffset;
quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
- quad.w = textSize.height;
+ quad.w = lineHeight;
}
- else if(i == 0u) // The first glyph in the whole text
+ else if((lineIndex != prevLineIndex) || (i == 0u)) // The first glyph in the line
{
quad.x = position.x;
- quad.y = 0.0f;
+ quad.y = yLineOffset;
quad.z = quad.x - glyph.xBearing + glyph.advance;
- quad.w = textSize.height;
+ quad.w = quad.y + lineHeight;
}
else if(i == glyphSize - 1u) // The last glyph in the whole text
{
quad.x = position.x - glyph.xBearing;
- quad.y = 0.0f;
+ quad.y = yLineOffset;
quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
- quad.w = textSize.height;
+ quad.w = quad.y + lineHeight;
}
else // The glyph in the middle of the text
{
quad.x = position.x - glyph.xBearing;
- quad.y = 0.0f;
+ quad.y = yLineOffset;
quad.z = quad.x + glyph.advance;
- quad.w = textSize.height;
+ quad.w = quad.y + lineHeight;
}
BackgroundVertex vertex;
numberOfQuads++;
}
+
+ if(lineIndex != prevLineIndex)
+ {
+ prevLineIndex = lineIndex;
+ }
}
// Only create the background actor if there are glyphs with background color
return actor;
}
+void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
+{
+ //Underlined character runs for markup-processor
+ const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
+ const Vector<GlyphIndex>& charactersToGlyph = mModel->mVisualModel->mCharactersToGlyph;
+ const Vector<Length>& glyphsPerCharacter = mModel->mVisualModel->mGlyphsPerCharacter;
+
+ if(shouldClearPreUnderlineRuns)
+ {
+ mModel->mVisualModel->mUnderlineRuns.Clear();
+ }
+
+ for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
+ {
+ CharacterIndex characterIndex = it->characterRun.characterIndex;
+ Length numberOfCharacters = it->characterRun.numberOfCharacters;
+ for(Length index = 0u; index < numberOfCharacters; index++)
+ {
+ GlyphRun underlineGlyphRun;
+ underlineGlyphRun.glyphIndex = charactersToGlyph[characterIndex + index];
+ underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
+ mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
+ }
+ }
+}
+
} // namespace Text
} // namespace Toolkit