29#include <com/sun/star/accessibility/AccessibleTextType.hpp>
30#include <com/sun/star/container/XEnumerationAccess.hpp>
31#include <com/sun/star/i18n/BreakIterator.hpp>
32#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
33#include <com/sun/star/i18n/ScriptDirection.hpp>
34#include <com/sun/star/i18n/WordType.hpp>
35#include <com/sun/star/rendering/CompositeOperation.hpp>
36#include <com/sun/star/rendering/TextDirection.hpp>
37#include <com/sun/star/text/WritingMode2.hpp>
51 sal_Int32 Signum (
const sal_Int32
nValue)
67 const Reference<XComponentContext>& rxContext,
68 const Reference<rendering::XCanvas>& rxCanvas,
69 const ::std::function<
void (
const css::awt::Rectangle&)>& rInvalidator)
75 [this] (sal_Int32 const nParagraphIndex, sal_Int32 const nCharacterIndex)
76 {
return this->
GetCaretBounds(nParagraphIndex, nCharacterIndex); },
80 mbIsFormatPending(
false)
82 Reference<lang::XMultiComponentFactory>
xFactory =
83 rxContext->getServiceManager();
88 mxBreakIterator = i18n::BreakIterator::create(rxContext);
92 mxScriptTypeDetector.set(
94 "com.sun.star.i18n.ScriptTypeDetector",
103 Reference<container::XEnumerationAccess> xParagraphAccess (rxText, UNO_QUERY);
104 if ( ! xParagraphAccess.is())
107 Reference<container::XEnumeration> xParagraphs =
108 xParagraphAccess->createEnumeration();
109 if ( ! xParagraphs.is())
115 sal_Int32 nCharacterCount (0);
116 while (xParagraphs->hasMoreElements())
122 Reference<text::XTextRange>(xParagraphs->nextElement(), UNO_QUERY),
124 pParagraph->SetupCellArray(
mpFont);
125 pParagraph->SetCharacterOffset(nCharacterCount);
126 nCharacterCount += pParagraph->GetCharacterCount();
137 const ::std::function<
void ()>& rBroadcaster)
148 rxParagraph->SetOrigin(
171 return nTotalHeight + rxParagraph->GetTotalTextHeight();
193 const sal_Int32 nDistance,
194 const sal_Int16 nTextType)
201 if (
mpCaret->GetParagraphIndex() < 0)
207 sal_Int32 nParagraphIndex (
mpCaret->GetParagraphIndex());
208 sal_Int32 nCharacterIndex (
mpCaret->GetCharacterIndex());
212 case AccessibleTextType::CHARACTER:
213 nCharacterIndex += nDistance;
216 case AccessibleTextType::WORD:
218 sal_Int32 nRemainingDistance (nDistance);
219 while (nRemainingDistance != 0)
224 const sal_Int32 nDelta (Signum(nDistance));
225 nCharacterIndex = pParagraph->GetWordBoundary(nCharacterIndex, nDelta);
226 if (nCharacterIndex < 0)
229 nParagraphIndex += nDelta;
230 if (nParagraphIndex < 0)
234 nRemainingDistance = 0;
241 nCharacterIndex = pParagraph->GetCharacterCount();
242 nRemainingDistance = 0;
246 nRemainingDistance -= nDelta;
254 nCharacterIndex = pParagraph->GetCharacterCount();
261 nRemainingDistance -= nDelta;
271 mpCaret->SetPosition(nParagraphIndex, nCharacterIndex);
275 const css::awt::Rectangle& rUpdateBox)
289 const sal_Int32 nAdditionalLeftBorder (10);
290 const sal_Int32 nAdditionalRightBorder (5);
293 const sal_Int32 nClipLeft (::std::max(
295 const sal_Int32 nClipTop (::std::max(
297 const sal_Int32 nClipRight (::std::min(
299 const sal_Int32 nClipBottom (::std::min(
301 if (nClipLeft>=nClipRight || nClipTop>=nClipBottom)
304 const awt::Rectangle aClipBox(
307 nClipRight - nClipLeft,
308 nClipBottom - nClipTop);
309 Reference<rendering::XPolyPolygon2D> xClipPolygon (
312 const rendering::ViewState aViewState(
313 geometry::AffineMatrix2D(1,0,0, 0,1,0),
316 rendering::RenderState aRenderState (
317 geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
320 rendering::CompositeOperation::SOURCE);
336 aRenderState.AffineTransform.m02 = 0;
337 aRenderState.AffineTransform.m12 = 0;
339#ifdef SHOW_CHARACTER_BOXES
342 nParagraphIndex<nParagraphCount;
348 for (sal_Int32 nCharacterIndex(0),nCharacterCount(pParagraph->GetCharacterCount());
349 nCharacterIndex<nCharacterCount; ++nCharacterIndex)
351 const awt::Rectangle aBox (pParagraph->GetCharacterBounds(nCharacterIndex,
false));
380 sal_Int32 nParagraphIndex,
381 const sal_Int32 nCharacterIndex)
const
386 return pParagraph->GetCharacterBounds(nCharacterIndex,
true);
388 return awt::Rectangle(0,0,0,0);
406 nY += rxParagraph->GetTotalTextHeight();
419 const sal_Int32 nParagraphIndex)
const
421 if (nParagraphIndex < 0)
432 const sal_Int32 nParagraphIndex,
433 const Reference<i18n::XBreakIterator>& rxBreakIterator,
434 const Reference<i18n::XScriptTypeDetector>& rxScriptTypeDetector,
435 const Reference<text::XTextRange>& rxTextRange,
438 mpCaret(
std::move(xCaret)),
439 mxBreakIterator(rxBreakIterator),
440 mxScriptTypeDetector(rxScriptTypeDetector),
448 mnWritingMode (
text::WritingMode2::LR_TB),
451 if (!rxTextRange.is())
454 Reference<beans::XPropertySet> xProperties (rxTextRange, UNO_QUERY);
457 xProperties->getPropertyValue(
"WritingMode") >>=
mnWritingMode;
459 catch(beans::UnknownPropertyException&)
468 const Reference<rendering::XCanvas>& rxCanvas,
469 const geometry::RealSize2D& rSize,
471 const rendering::ViewState& rViewState,
472 rendering::RenderState& rRenderState,
473 const double nTopOffset,
474 const double nClipTop,
475 const double nClipBottom)
482 const double nSavedM12 (rRenderState.AffineTransform.m12);
485 rRenderState.AffineTransform.m02 += rSize.Width;
487#ifdef SHOW_CHARACTER_BOXES
507 else if (nLineTop > nClipBottom)
511 rRenderState.AffineTransform.m12 = nSavedM12 + rLine.
mnBaseLine;
513 rxCanvas->drawTextLayout (
518 rRenderState.AffineTransform.m12 = nSavedM12;
521 rRenderState.AffineTransform.m02 -= rSize.Width;
534 if ( ! rpFont || ! rpFont->mxFont.is())
537 sal_Int32 nPosition (0);
548 const rendering::FontMetrics aMetrics (rpFont->mxFont->getFontMetrics());
551 mnLineHeight = aMetrics.Ascent + aMetrics.Descent + aMetrics.ExternalLeading;
553 i18n::Boundary aCurrentLine(0,0);
560 i18n::WordType::ANYWORD_IGNOREWHITESPACES);
561 AddWord(nWidth, aCurrentLine, aWordBoundary.startPos, rpFont);
568 if (aWordBoundary.endPos>aWordBoundary.startPos)
569 AddWord(nWidth, aCurrentLine, aWordBoundary.endPos, rpFont);
571 if (aWordBoundary.startPos<0 || aWordBoundary.endPos<0)
573 if (nPosition >= aWordBoundary.endPos)
575 nPosition = aWordBoundary.endPos;
578 if (aCurrentLine.endPos>aCurrentLine.startPos)
584 const sal_Int32 nLocalCharacterIndex,
585 const sal_Int32 nDistance)
587 OSL_ASSERT(nDistance==-1 || nDistance==+1);
589 if (nLocalCharacterIndex < 0)
626 return mpCaret->GetCharacterIndex();
659 i18n::Boundary& rCurrentLine,
660 const sal_Int32 nWordBoundary,
663 sal_Int32 nLineStart (0);
665 nLineStart = rCurrentLine.startPos;
667 const OUString sLineCandidate (
670 css::geometry::RealRectangle2D aLineBox (
675 const double nLineWidth (aLineBox.X2 - aLineBox.X1);
682 rCurrentLine.endPos = nWordBoundary;
686 i18n::Boundary& rCurrentLine)
688 Line aLine (rCurrentLine.startPos, rCurrentLine.endPos);
703 for ( ; nCellIndex<sal_Int32(
maCells.size()); ++nCellIndex)
715 rCurrentLine.startPos = rCurrentLine.endPos;
734 const sal_Int32 nGlobalCharacterIndex)
const
753 const sal_Int32 nOffset,
754 const sal_Int32 nIndex,
755 const sal_Int16 nTextType)
const
759 case AccessibleTextType::PARAGRAPH:
765 case AccessibleTextType::SENTENCE:
780 case AccessibleTextType::WORD:
785 case AccessibleTextType::LINE:
788 [
nIndex](
const Line& rLine) { return nIndex < rLine.mnLineEndCharacterIndex; });
793 iLine->mnLineStartCharacterIndex,
794 iLine->mnLineEndCharacterIndex - iLine->mnLineStartCharacterIndex),
795 iLine->mnLineStartCharacterIndex,
796 iLine->mnLineEndCharacterIndex);
803 case AccessibleTextType::CHARACTER:
804 case AccessibleTextType::GLYPH:
805 case AccessibleTextType::ATTRIBUTE_RUN:
809 return TextSegment(OUString(), 0,0);
813 const sal_Int32 nOffset,
814 const sal_Int32 nIndex)
const
816 sal_Int32 nCurrentOffset (nOffset);
817 sal_Int32 nCurrentIndex (
nIndex);
819 i18n::Boundary aWordBoundary;
820 if (nCurrentOffset == 0)
825 i18n::WordType::ANYWORD_IGNOREWHITESPACES,
827 else if (nCurrentOffset < 0)
829 while (nCurrentOffset<0 && nCurrentIndex>0)
835 i18n::WordType::ANYWORD_IGNOREWHITESPACES);
836 nCurrentIndex = aWordBoundary.startPos;
848 i18n::WordType::ANYWORD_IGNOREWHITESPACES);
849 nCurrentIndex = aWordBoundary.endPos;
858 sal_Int32 nStartIndex,
859 sal_Int32 nEndIndex)
const
861 if (nEndIndex <= nStartIndex)
874 sal_Int32 nGlobalCharacterIndex,
875 const bool bCaretBox)
882 for (sal_Int32 nLineIndex=0,nLineCount=
maLines.size();
883 nLineIndex<nLineCount;
890 if (nLineIndex<nLineCount-1)
900 geometry::RealRectangle2D rCellBox (rLine.
maCellBoxes[
901 ::std::min(nCellIndex, rLine.
maCellBoxes.getLength()-1)]);
903 double nLeft = nX + rCellBox.X1;
904 double nRight = nX + rCellBox.X2;
905 if (nTextDirection == rendering::TextDirection::WEAK_RIGHT_TO_LEFT)
907 const double nOldRight (nRight);
908 nRight = rLine.
mnWidth - nLeft;
909 nLeft = rLine.
mnWidth - nOldRight;
926 const sal_Int32 nX1 = sal_Int32(floor(nLeft));
927 const sal_Int32 nY1 = sal_Int32(floor(nTop));
928 const sal_Int32 nX2 = sal_Int32(ceil(nRight));
929 const sal_Int32 nY2 = sal_Int32(ceil(nBottom));
931 return awt::Rectangle(nX1,nY1,nX2-nX1+1,nY2-nY1+1);
937 return awt::Rectangle(sal_Int32(nX+0.5), sal_Int32(nY+0.5), 0, 0);
943 sal_Int32 nPosition (0);
945 while (nPosition < nTextLength)
947 const sal_Int16 nScriptDirection (
950 switch (nScriptDirection)
952 case i18n::ScriptDirection::NEUTRAL:
955 case i18n::ScriptDirection::LEFT_TO_RIGHT:
956 return rendering::TextDirection::WEAK_LEFT_TO_RIGHT;
958 case i18n::ScriptDirection::RIGHT_TO_LEFT:
959 return rendering::TextDirection::WEAK_RIGHT_TO_LEFT;
968 sal_Int8 nTextDirection(rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
971 case text::WritingMode2::LR_TB:
972 nTextDirection = rendering::TextDirection::WEAK_LEFT_TO_RIGHT;
975 case text::WritingMode2::RL_TB:
976 nTextDirection = rendering::TextDirection::WEAK_RIGHT_TO_LEFT;
980 case text::WritingMode2::TB_RL:
981 case text::WritingMode2::TB_LR:
985 return nTextDirection;
998 if ( ! rpFont || ! rpFont->mxFont.is())
1001 sal_Int32 nPosition (0);
1005 while (nPosition < nTextLength)
1011 i18n::CharacterIteratorMode::SKIPCELL,
1015 rendering::StringContext aContext (
msParagraphText, nPosition, nNewPosition-nPosition);
1016 Reference<rendering::XTextLayout> xLayout (
1017 rpFont->mxFont->createTextLayout(aContext, nTextDirection, 0));
1018 css::geometry::RealRectangle2D aCharacterBox (xLayout->queryTextBounds());
1022 nNewPosition-nPosition,
1023 aCharacterBox.X2-aCharacterBox.X1);
1025 nPosition = nNewPosition;
1032 uno::Reference<uno::XComponentContext>
const& xContext,
1033 ::std::function<css::awt::Rectangle (
const sal_Int32,
const sal_Int32)> aCharacterBoundsAccess,
1034 ::std::function<
void (
const css::awt::Rectangle&)> aInvalidator)
1037 mnCharacterIndex(-1),
1038 mnCaretBlinkTaskId(0),
1039 mbIsCaretVisible(false),
1040 maCharacterBoundsAccess(
std::move(aCharacterBoundsAccess)),
1041 maInvalidator(
std::move(aInvalidator))
1051 catch (uno::Exception
const&)
1063 [
this] (TimeValue
const&) {
return this->
InvertCaret(); },
1085 const sal_Int32 nParagraphIndex,
1086 const sal_Int32 nCharacterIndex)
1118 const ::std::function<
void (sal_Int32,sal_Int32,sal_Int32,sal_Int32)>& rBroadcaster)
1138 const sal_Int32 nCharacterIndex,
1139 const sal_Int32 nCharacterCount,
1141 : mnCharacterIndex(nCharacterIndex),
1142 mnCharacterCount(nCharacterCount),
1150 const sal_Int32 nLineStartCharacterIndex,
1151 const sal_Int32 nLineEndCharacterIndex)
1152 : mnLineStartCharacterIndex(nLineStartCharacterIndex),
1153 mnLineEndCharacterIndex(nLineEndCharacterIndex),
1154 mnLineStartCellIndex(-1), mnLineEndCellIndex(-1),
1161 if ( mnLineStartCharacterIndex < mnLineEndCharacterIndex && !maCellBoxes.hasElements() )
1163 if (mxLayoutedLine.is())
1164 maCellBoxes = mxLayoutedLine->queryInkMeasures();
1167 OSL_ASSERT(mxLayoutedLine.is());
1173 const OUString& rsParagraphText,
1177 if ( ! mxLayoutedLine.is())
1179 const rendering::StringContext aContext (
1181 mnLineStartCharacterIndex,
1182 mnLineEndCharacterIndex - mnLineStartCharacterIndex);
1184 mxLayoutedLine = rpFont->mxFont->createTextLayout(
Reference< XComponentContext > m_xContext
geometry::RealSize2D maSize
const sal_Int64 CaretBlinkInterval
Reference< rendering::XCanvas > mxCanvas
static void SetDeviceColor(css::rendering::RenderState &rRenderState, const css::util::Color aColor)
static css::geometry::RealRectangle2D GetTextBoundingBox(const css::uno::Reference< css::rendering::XCanvasFont > &rxFont, const OUString &rsText, const sal_Int8=css::rendering::TextDirection::WEAK_LEFT_TO_RIGHT)
static sal_Int32 Round(const double nValue)
static css::uno::Reference< css::rendering::XPolyPolygon2D > CreatePolygon(const css::awt::Rectangle &rBox, const css::uno::Reference< css::rendering::XGraphicDevice > &rxDevice)
const css::awt::Rectangle & GetBounds() const
sal_Int32 mnParagraphIndex
css::uno::Reference< css::uno::XComponentContext > const & m_xContext
sal_Int32 mnCharacterIndex
void SetCaretMotionBroadcaster(const ::std::function< void(sal_Int32, sal_Int32, sal_Int32, sal_Int32)> &rBroadcaster)
Set a (possibly empty) functor that broadcasts changes of the caret position.
css::awt::Rectangle maCaretBounds
const ::std::function< css::awt::Rectangle(const sal_Int32, const sal_Int32)> maCharacterBoundsAccess
void SetPosition(const sal_Int32 nParagraphIndex, const sal_Int32 nCharacterIndex)
sal_Int32 mnCaretBlinkTaskId
PresenterTextCaret(css::uno::Reference< css::uno::XComponentContext > const &xContext, ::std::function< css::awt::Rectangle(const sal_Int32, const sal_Int32)> aCharacterBoundsAccess, ::std::function< void(const css::awt::Rectangle &)> aInvalidator)
::std::function< void(sal_Int32, sal_Int32, sal_Int32, sal_Int32)> maBroadcaster
const ::std::function< void(const css::awt::Rectangle &)> maInvalidator
A portion of a string that encodes one unicode cell.
sal_Int32 mnCharacterCount
Cell(const sal_Int32 nCharacterIndex, const sal_Int32 nCharacterCount, const double nCellWidth)
sal_Int32 mnCharacterIndex
sal_Int32 mnLineEndCharacterIndex
sal_Int32 mnLineStartCellIndex
sal_Int32 mnLineStartCharacterIndex
Line(const sal_Int32 nLineStartCharacterIndex, const sal_Int32 nLineEndCharacterIndex)
css::uno::Sequence< css::geometry::RealRectangle2D > maCellBoxes
css::uno::Reference< css::rendering::XTextLayout > mxLayoutedLine
sal_Int32 mnLineEndCellIndex
void ProvideLayoutedLine(const OUString &rsParagraphText, const PresenterTheme::SharedFontDescriptor &rpFont, const sal_Int8 nTextDirection)
sal_Unicode GetCharacter(const sal_Int32 nGlobalCharacterIndex) const
void SetCaretPosition(const sal_Int32 nPosition) const
css::accessibility::TextSegment GetTextSegment(const sal_Int32 nOffset, const sal_Int32 nGlobalCharacterIndex, const sal_Int16 nTextType) const
double GetTotalTextHeight() const
css::uno::Reference< css::i18n::XScriptTypeDetector > mxScriptTypeDetector
void AddLine(css::i18n::Boundary &rCurrentLine)
void SetupCellArray(const PresenterTheme::SharedFontDescriptor &rpFont)
css::awt::Point GetRelativeLocation() const
sal_Int8 GetTextDirection() const
sal_Int32 mnCharacterOffset
The index of the first character in this paragraph with respect to the whole text.
::std::vector< Cell > maCells
sal_Int32 GetWordBoundary(const sal_Int32 nLocalCharacterIndex, const sal_Int32 nDistance)
sal_Int32 GetCaretPosition() const
const OUString & GetText() const
sal_Int32 GetCharacterCount() const
css::accessibility::TextSegment CreateTextSegment(sal_Int32 nStartIndex, sal_Int32 nEndIndex) const
void SetCharacterOffset(const sal_Int32 nCharacterOffset)
css::awt::Size GetSize() const
PresenterTextParagraph(const sal_Int32 nParagraphIndex, const css::uno::Reference< css::i18n::XBreakIterator > &rxBreakIterator, const css::uno::Reference< css::i18n::XScriptTypeDetector > &rxScriptTypeDetector, const css::uno::Reference< css::text::XTextRange > &rxTextRange, SharedPresenterTextCaret xCaret)
css::uno::Reference< css::i18n::XBreakIterator > mxBreakIterator
void AddWord(const double nWidth, css::i18n::Boundary &rCurrentLine, const sal_Int32 nWordBoundary, const PresenterTheme::SharedFontDescriptor &rpFont)
css::awt::Rectangle GetCharacterBounds(sal_Int32 nGlobalCharacterIndex, const bool bCaretBox)
const sal_Int32 mnParagraphIndex
::std::vector< sal_Int32 > maWordBoundaries
bool IsTextReferencePointLeft() const
css::accessibility::TextSegment GetWordTextSegment(const sal_Int32 nOffset, const sal_Int32 nIndex) const
SharedPresenterTextCaret mpCaret
void SetOrigin(const double nXOrigin, const double nYOrigin)
::std::vector< Line > maLines
void Paint(const css::uno::Reference< css::rendering::XCanvas > &rxCanvas, const css::geometry::RealSize2D &rSize, const PresenterTheme::SharedFontDescriptor &rpFont, const css::rendering::ViewState &rViewState, css::rendering::RenderState &rRenderState, const double nTopOffset, const double nClipTop, const double nClipBottom)
void Format(const double nY, const double nWidth, const PresenterTheme::SharedFontDescriptor &rpFont)
void MoveCaret(const sal_Int32 nDistance, const sal_Int16 nTextType)
Move the caret forward or backward by character or by word.
css::geometry::RealPoint2D maLocation
double GetTotalTextHeight()
void SetSize(const css::geometry::RealSize2D &rSize)
css::uno::Reference< css::i18n::XBreakIterator > mxBreakIterator
sal_Int32 GetParagraphCount() const
css::uno::Reference< css::i18n::XScriptTypeDetector > mxScriptTypeDetector
::std::vector< SharedPresenterTextParagraph > maParagraphs
PresenterTextView(const css::uno::Reference< css::uno::XComponentContext > &rxContext, const css::uno::Reference< css::rendering::XCanvas > &rxCanvas, const ::std::function< void(const css::awt::Rectangle &)> &rInvalidator)
::std::function< void()> maTextChangeBroadcaster
void SetText(const css::uno::Reference< css::text::XText > &rxText)
const SharedPresenterTextCaret & GetCaret() const
void SetLocation(const css::geometry::RealPoint2D &rLocation)
void Paint(const css::awt::Rectangle &rUpdateBox)
SharedPresenterTextParagraph GetParagraph(const sal_Int32 nParagraphIndex) const
PresenterTheme::SharedFontDescriptor mpFont
SharedPresenterTextCaret mpCaret
void SetOffset(const double nLeft, const double nTop)
void SetFont(const PresenterTheme::SharedFontDescriptor &rpFont)
css::geometry::RealSize2D maSize
css::awt::Rectangle GetCaretBounds(const sal_Int32 nParagraphIndex, const sal_Int32 nCharacterIndex) const
css::uno::Reference< css::rendering::XCanvas > mxCanvas
void SetTextChangeBroadcaster(const ::std::function< void()> &rBroadcaster)
std::shared_ptr< FontDescriptor > SharedFontDescriptor
static void CancelTask(const sal_Int32 nTaskId)
static sal_Int32 ScheduleRepeatedTask(const css::uno::Reference< css::uno::XComponentContext > &xContext, const Task &rTask, const sal_Int64 nFirst, const sal_Int64 nInterval)
Schedule a task to be executed repeatedly.
#define TOOLS_WARN_EXCEPTION(area, stream)
Reference< XSingleServiceFactory > xFactory
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
std::shared_ptr< T > make_shared(Args &&... args)
const sal_Int32 nCellWidth
std::shared_ptr< PresenterTextParagraph > SharedPresenterTextParagraph
std::shared_ptr< PresenterTextCaret > SharedPresenterTextCaret
sal_Int16 mnParagraphIndex