/*
- * 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.
#include <dali/devel-api/adaptor-framework/window-devel.h>
#include <dali/integration-api/debug.h>
#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/rendering/renderer.h>
#include <cmath>
// INTERNAL INCLUDES
#include <dali-toolkit/internal/text/character-set-conversion.h>
#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
#include <dali-toolkit/internal/text/text-control-interface.h>
#include <dali-toolkit/internal/text/text-controller-impl-data-clearer.h>
#include <dali-toolkit/internal/text/text-controller-impl-event-handler.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>
+#include <dali-toolkit/internal/text/underlined-glyph-run.h>
using namespace Dali;
}
}
+void UpdateCursorPositionForAlignment(Controller::Impl& impl, bool needFullAlignment)
+{
+ EventData* eventData = impl.mEventData;
+
+ // Set the flag to redo the alignment operation
+ impl.mOperationsPending = static_cast<Controller::OperationsMask>(impl.mOperationsPending | Controller::OperationsMask::ALIGN);
+
+ if(eventData)
+ {
+ // Note: mUpdateAlignment is currently only needed for horizontal alignment
+ eventData->mUpdateAlignment = needFullAlignment;
+
+ // Update the cursor if it's in editing mode
+ if(EventData::IsEditingState(eventData->mState))
+ {
+ impl.ChangeState(EventData::EDITING);
+ eventData->mUpdateCursorPosition = true;
+ }
+ }
+}
+
} // unnamed Namespace
EventData::EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
if(mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::LOCALE ||
(mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::INHERIT && !mIsLayoutDirectionChanged))
{
- return static_cast<Dali::LayoutDirection::Type>(DevelWindow::Get(actor).GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+ Window window = DevelWindow::Get(actor);
+ return static_cast<Dali::LayoutDirection::Type>(window ? window.GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>() : LayoutDirection::LEFT_TO_RIGHT);
}
else
{
if(nullptr == mFontDefaults)
{
TextAbstraction::FontDescription fontDescription;
- defaultFontId = mFontClient.GetFontId(fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale);
+ defaultFontId = mFontClient.GetFontId(fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * GetFontSizeScale());
}
else
{
- defaultFontId = mFontDefaults->GetFontId(mFontClient, mFontDefaults->mDefaultPointSize * mFontSizeScale);
+ defaultFontId = mFontDefaults->GetFontId(mFontClient, mFontDefaults->mDefaultPointSize * GetFontSizeScale());
}
Text::FontMetrics fontMetrics;
{
mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
- RelayoutForNewLineSize();
+ RelayoutAllCharacters();
return true;
}
return false;
{
mLayoutEngine.SetDefaultLineSize(lineSize);
- RelayoutForNewLineSize();
+ RelayoutAllCharacters();
+ return true;
+ }
+ return false;
+}
+
+bool Controller::Impl::SetRelativeLineSize(float relativeLineSize)
+{
+ if(std::fabs(relativeLineSize - GetRelativeLineSize()) > Math::MACHINE_EPSILON_1000)
+ {
+ mLayoutEngine.SetRelativeLineSize(relativeLineSize);
+
+ RelayoutAllCharacters();
return true;
}
return false;
}
+float Controller::Impl::GetRelativeLineSize()
+{
+ return mLayoutEngine.GetRelativeLineSize();
+}
+
string Controller::Impl::GetSelectedText()
{
string text;
if(mEventData->mDecorator)
{
- mEventData->mDecorator->SetEditable(editable);
+ bool decoratorEditable = editable && mIsUserInteractionEnabled;
+ mEventData->mDecorator->SetEditable(decoratorEditable);
}
}
}
parameters.logical = logical;
parameters.isMultiline = isMultiLine;
+ float defaultFontLineHeight = GetDefaultFontLineHeight();
+
Text::GetCursorPosition(parameters,
+ defaultFontLineHeight,
cursorInfo);
// Adds Outline offset.
{
mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
}
+ else if(mModel->mLogicalModel->mText.Count() == 0u)
+ {
+ Relayouter::CalculateVerticalOffset(*this, mModel->mVisualModel->mControlSize);
+ }
}
}
}
}
-void Controller::Impl::RelayoutForNewLineSize()
+void Controller::Impl::RelayoutAllCharacters()
{
// relayout all characters
mTextUpdateInfo.mCharacterIndex = 0;
{
CharacterIndex characterIndex = it->characterRun.characterIndex;
Length numberOfCharacters = it->characterRun.numberOfCharacters;
- for(Length index = 0u; index < numberOfCharacters; index++)
+
+ if(numberOfCharacters == 0)
+ {
+ continue;
+ }
+
+ // Create one run for all glyphs of all run's characters that has same properties
+ // This enhance performance and reduce the needed memory to store glyphs-runs
+ UnderlinedGlyphRun underlineGlyphRun;
+ underlineGlyphRun.glyphRun.glyphIndex = charactersToGlyph[characterIndex];
+ underlineGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex];
+ //Copy properties (attributes)
+ underlineGlyphRun.properties = it->properties;
+
+ for(Length index = 1u; index < numberOfCharacters; index++)
{
- GlyphRun underlineGlyphRun;
- underlineGlyphRun.glyphIndex = charactersToGlyph[characterIndex + index];
- underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
- mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
+ underlineGlyphRun.glyphRun.numberOfGlyphs += glyphsPerCharacter[characterIndex + index];
}
+
+ mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
+ }
+}
+
+void Controller::Impl::CopyStrikethroughFromLogicalToVisualModels()
+{
+ //Strikethrough character runs from markup-processor
+ const Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns = mModel->mLogicalModel->mStrikethroughCharacterRuns;
+ const Vector<GlyphIndex>& charactersToGlyph = mModel->mVisualModel->mCharactersToGlyph;
+ const Vector<Length>& glyphsPerCharacter = mModel->mVisualModel->mGlyphsPerCharacter;
+
+ mModel->mVisualModel->mStrikethroughRuns.Clear();
+
+ for(Vector<StrikethroughCharacterRun>::ConstIterator it = strikethroughCharacterRuns.Begin(), endIt = strikethroughCharacterRuns.End(); it != endIt; ++it)
+ {
+ CharacterIndex characterIndex = it->characterRun.characterIndex;
+ Length numberOfCharacters = it->characterRun.numberOfCharacters;
+
+ if(numberOfCharacters == 0)
+ {
+ continue;
+ }
+
+ StrikethroughGlyphRun strikethroughGlyphRun;
+ strikethroughGlyphRun.properties = it->properties;
+ strikethroughGlyphRun.glyphRun.glyphIndex = charactersToGlyph[characterIndex];
+ strikethroughGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex];
+
+ for(Length index = 1u; index < numberOfCharacters; index++)
+ {
+ strikethroughGlyphRun.glyphRun.numberOfGlyphs += glyphsPerCharacter[characterIndex + index];
+ }
+
+ mModel->mVisualModel->mStrikethroughRuns.PushBack(strikethroughGlyphRun);
+ }
+}
+
+void Controller::Impl::CopyCharacterSpacingFromLogicalToVisualModels()
+{
+ //CharacterSpacing character runs from markup-processor
+ const Vector<CharacterSpacingCharacterRun>& characterSpacingCharacterRuns = mModel->mLogicalModel->mCharacterSpacingCharacterRuns;
+ const Vector<GlyphIndex>& charactersToGlyph = mModel->mVisualModel->mCharactersToGlyph;
+ const Vector<Length>& glyphsPerCharacter = mModel->mVisualModel->mGlyphsPerCharacter;
+
+ mModel->mVisualModel->mCharacterSpacingRuns.Clear();
+
+ for(Vector<CharacterSpacingCharacterRun>::ConstIterator it = characterSpacingCharacterRuns.Begin(), endIt = characterSpacingCharacterRuns.End(); it != endIt; ++it)
+ {
+ const CharacterIndex& characterIndex = it->characterRun.characterIndex;
+ const Length& numberOfCharacters = it->characterRun.numberOfCharacters;
+
+ if(numberOfCharacters == 0)
+ {
+ continue;
+ }
+
+ CharacterSpacingGlyphRun characterSpacingGlyphRun;
+ characterSpacingGlyphRun.value = it->value;
+ characterSpacingGlyphRun.glyphRun.glyphIndex = charactersToGlyph[characterIndex];
+ characterSpacingGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex];
+
+ for(Length index = 1u; index < numberOfCharacters; index++)
+ {
+ characterSpacingGlyphRun.glyphRun.numberOfGlyphs += glyphsPerCharacter[characterIndex + index];
+ }
+
+ mModel->mVisualModel->mCharacterSpacingRuns.PushBack(characterSpacingGlyphRun);
}
}
{
// Set the alignment.
mModel->mHorizontalAlignment = alignment;
-
- // Set the flag to redo the alignment operation.
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending | ALIGN);
-
- if(mEventData)
- {
- mEventData->mUpdateAlignment = true;
-
- // Update the cursor if it's in editing mode
- if(EventData::IsEditingState(mEventData->mState))
- {
- ChangeState(EventData::EDITING);
- mEventData->mUpdateCursorPosition = true;
- }
- }
-
+ UpdateCursorPositionForAlignment(*this, true);
RequestRelayout();
}
}
{
// Set the alignment.
mModel->mVerticalAlignment = alignment;
- mOperationsPending = static_cast<OperationsMask>(mOperationsPending | ALIGN);
+ UpdateCursorPositionForAlignment(*this, false);
RequestRelayout();
}
}
}
}
+void Controller::Impl::SetUserInteractionEnabled(bool enabled)
+{
+ mIsUserInteractionEnabled = enabled;
+
+ if(mEventData && mEventData->mDecorator)
+ {
+ bool editable = mEventData->mEditingEnabled && enabled;
+ mEventData->mDecorator->SetEditable(editable);
+ }
+}
+
void Controller::Impl::ClearFontData()
{
if(mFontDefaults)
{
mModel->mLogicalModel->mColorRuns.Clear();
mModel->mLogicalModel->ClearFontDescriptionRuns();
+ mModel->mLogicalModel->ClearStrikethroughRuns();
}
void Controller::Impl::ResetScrollPosition()