X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Ftext-controls%2Fcommon-text-utils.cpp;h=c1f4179d3e3372d7a345ffc3cf4542e3165ac4f5;hb=ff6ce970724ccc8bee65f7c93411b274907c09d7;hp=696b44ad63291cc5edfdf11a9590b1b853a44d1a;hpb=70468ae7ba6b75df1db1063e9b3fcf0313ffd787;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-toolkit/internal/controls/text-controls/common-text-utils.cpp b/dali-toolkit/internal/controls/text-controls/common-text-utils.cpp index 696b44a..c1f4179 100644 --- a/dali-toolkit/internal/controls/text-controls/common-text-utils.cpp +++ b/dali-toolkit/internal/controls/text-controls/common-text-utils.cpp @@ -14,11 +14,16 @@ * limitations under the License. */ +// EXTERNAL INCLUDES #include +// INTERNAL INCLUDES #include #include +#include #include +#include +#include #include namespace Dali::Toolkit::Internal @@ -50,6 +55,7 @@ void CommonTextUtils::RenderText( float& alignmentOffset, Actor& renderableActor, Actor& backgroundActor, + Actor& cursorLayerActor, Toolkit::Control& stencil, std::vector& clippingDecorationActors, std::vector& anchorActors, @@ -147,8 +153,354 @@ void CommonTextUtils::RenderText( backgroundActor.LowerToBottom(); } } + + if(cursorLayerActor) + { + cursorLayerActor.RaiseToTop(); + } + SynchronizeTextAnchorsInParent(textActor, controller, anchorActors); } } +std::size_t TextControlAccessible::GetCharacterCount() const +{ + return GetWholeText().size(); +} + +std::size_t TextControlAccessible::GetCursorOffset() const +{ + return 0u; +} + +Rect<> TextControlAccessible::GetRangeExtents(std::size_t startOffset, std::size_t endOffset, Accessibility::CoordinateType type) +{ + if(!ValidateRange(GetWholeText(), startOffset, endOffset)) + { + return {0, 0, 0, 0}; + } + + auto rect = GetTextController()->GetTextBoundingRectangle(startOffset, endOffset - 1); + auto extents = GetExtents(type); + + rect.x += extents.x; + rect.y += extents.y; + + return rect; +} + +Accessibility::Range TextControlAccessible::GetRangeOfSelection(std::size_t selectionIndex) const +{ + // Since DALi supports only one selection, indices other than 0 are ignored + if(selectionIndex > 0) + { + return {}; + } + + auto indices = GetTextController()->GetSelectionIndexes(); + auto startOffset = static_cast(indices.first); + auto endOffset = static_cast(indices.second); + auto text = GetText(startOffset, endOffset); + + return {startOffset, endOffset, text}; +} + +std::string TextControlAccessible::GetText(std::size_t startOffset, std::size_t endOffset) const +{ + auto text = GetWholeText(); + + if(!ValidateRange(text, startOffset, endOffset)) + { + return {}; + } + + if(IsHiddenInput()) + { + std::uint32_t substituteCharacterUtf32 = GetSubstituteCharacter(); + std::string substituteCharacterUtf8; + std::string substituteText; + + Toolkit::Text::Utf32ToUtf8(&substituteCharacterUtf32, 1, substituteCharacterUtf8); + + while(substituteText.length() < endOffset - startOffset) + { + substituteText.append(substituteCharacterUtf8); + } + + return substituteText; + } + + return text.substr(startOffset, endOffset - startOffset); +} + +Accessibility::Range TextControlAccessible::GetTextAtOffset(std::size_t offset, Accessibility::TextBoundary boundary) const +{ + Accessibility::Range range{}; + + if(IsHiddenInput()) + { + // Returning empty object, as there is no possibility to parse the textfield + // when its content is hidden. + return range; + } + + auto text = GetWholeText(); + auto textSize = text.size(); + + switch(boundary) + { + case Dali::Accessibility::TextBoundary::CHARACTER: + { + if(offset < textSize) + { + range.content = text[offset]; + range.startOffset = offset; + range.endOffset = offset + 1; + } + break; + } + + case Dali::Accessibility::TextBoundary::WORD: + case Dali::Accessibility::TextBoundary::LINE: + { + std::vector breaks(textSize, '\0'); + + if(boundary == Dali::Accessibility::TextBoundary::WORD) + { + Accessibility::Accessible::FindWordSeparationsUtf8(reinterpret_cast(text.c_str()), textSize, "", breaks.data()); + } + else + { + Accessibility::Accessible::FindLineSeparationsUtf8(reinterpret_cast(text.c_str()), textSize, "", breaks.data()); + } + + std::size_t index = 0u; + std::size_t counter = 0u; + + while(index < textSize && counter <= offset) + { + auto start = index; + if(breaks[index]) + { + while(breaks[index]) + { + index++; + } + counter++; + } + else + { + if(boundary == Dali::Accessibility::TextBoundary::WORD) + { + index++; + } + if(boundary == Dali::Accessibility::TextBoundary::LINE) + { + counter++; + } + } + + if((counter > 0) && ((counter - 1) == offset)) + { + range.content = text.substr(start, index - start + 1); + range.startOffset = start; + range.endOffset = index + 1; + } + + if(boundary == Dali::Accessibility::TextBoundary::LINE) + { + index++; + } + } + break; + } + + case Dali::Accessibility::TextBoundary::SENTENCE: // Not supported by default + case Dali::Accessibility::TextBoundary::PARAGRAPH: // Not supported by libunibreak library + default: + { + break; + } + } + + return range; +} + +bool TextControlAccessible::RemoveSelection(std::size_t selectionIndex) +{ + // Since DALi supports only one selection, indices other than 0 are ignored + if(selectionIndex > 0) + { + return false; + } + + GetTextController()->SetSelection(0, 0); + + return true; +} + +bool TextControlAccessible::SetCursorOffset(std::size_t offset) +{ + return false; +} + +bool TextControlAccessible::SetRangeOfSelection(std::size_t selectionIndex, std::size_t startOffset, std::size_t endOffset) +{ + // Since DALi supports only one selection, indices other than 0 are ignored + if(selectionIndex > 0) + { + return false; + } + + // Lack of ValidateRange() is intentional + + GetTextController()->SetSelection(startOffset, endOffset); + + return true; +} + +Accessibility::Hyperlink* TextControlAccessible::GetLink(std::int32_t linkIndex) const +{ + if(linkIndex < 0 || linkIndex >= GetLinkCount()) + { + return nullptr; + } + + auto anchor = GetTextAnchors()[linkIndex]; + + return Accessibility::Hyperlink::DownCast(Accessibility::Accessible::Get(anchor)); +} + +std::int32_t TextControlAccessible::GetLinkCount() const +{ + return static_cast(GetTextAnchors().size()); +} + +std::int32_t TextControlAccessible::GetLinkIndex(std::int32_t characterOffset) const +{ + return GetTextController()->GetAnchorIndex(static_cast(characterOffset)); +} + +std::string TextControlAccessible::GetWholeText() const +{ + std::string text; + + GetTextController()->GetText(text); + + return text; +} + +std::uint32_t TextControlAccessible::GetSubstituteCharacter() const +{ + return Toolkit::Text::STAR; +} + +bool TextControlAccessible::IsHiddenInput() const +{ + return false; +} + +bool TextControlAccessible::ValidateRange(const std::string& string, std::size_t begin, std::size_t end) +{ + auto size = string.size(); + + if(end <= begin || begin >= size || end > size) + { + return false; + } + + // TODO: Check whether the range [begin, end) describes a valid substring: + // 1. It does not break multi-byte UTF-8 sequences. + // 2. It does not break graphemes (compound emojis, glyphs with combining characters etc.). + + return true; +} + +Accessibility::States EditableTextControlAccessible::CalculateStates() +{ + using Dali::Accessibility::State; + + auto states = DevelControl::ControlAccessible::CalculateStates(); + auto focusControl = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl(); + + states[State::EDITABLE] = true; + states[State::FOCUSABLE] = true; + states[State::FOCUSED] = (Self() == focusControl); + + return states; +} + +std::size_t EditableTextControlAccessible::GetCursorOffset() const +{ + return GetTextController()->GetCursorPosition(); +} + +bool EditableTextControlAccessible::SetCursorOffset(std::size_t offset) +{ + if(offset > GetCharacterCount()) + { + return false; + } + + GetTextController()->ResetCursorPosition(offset); + RequestTextRelayout(); + + return true; +} + +bool EditableTextControlAccessible::CopyText(std::size_t startPosition, std::size_t endPosition) +{ + auto text = GetWholeText(); + + if(!ValidateRange(text, startPosition, endPosition)) + { + return false; + } + + GetTextController()->CopyStringToClipboard(text.substr(startPosition, endPosition - startPosition)); + + return true; +} + +bool EditableTextControlAccessible::CutText(std::size_t startPosition, std::size_t endPosition) +{ + if(!CopyText(startPosition, endPosition)) + { + return false; + } + + return DeleteText(startPosition, endPosition); +} + +bool EditableTextControlAccessible::DeleteText(std::size_t startPosition, std::size_t endPosition) +{ + auto text = GetWholeText(); + + if(!ValidateRange(text, startPosition, endPosition)) + { + return false; + } + + return SetTextContents(text.erase(startPosition, endPosition - startPosition)); +} + +bool EditableTextControlAccessible::InsertText(std::size_t startPosition, std::string newText) +{ + auto text = GetWholeText(); + + if(!ValidateRange(text, startPosition, startPosition + 1)) + { + return false; + } + + return SetTextContents(text.insert(startPosition, std::move(newText))); +} + +bool EditableTextControlAccessible::SetTextContents(std::string newContents) +{ + GetTextController()->SetText(std::move(newContents)); + + return true; +} + } // namespace Dali::Toolkit::Internal