/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// Create the break iterator that we use to break text into lines.
mxBreakIterator = i18n::BreakIterator::create(rxContext);
// Create the script type detector that is used to split paragraphs into // portions of the same text direction.
mxScriptTypeDetector.set(
xFactory->createInstanceWithContext(
u"com.sun.star.i18n.ScriptTypeDetector"_ustr,
rxContext),
UNO_QUERY_THROW);
}
// When the caret has not been visible yet then move it to the beginning // of the text. if (mpCaret->GetParagraphIndex() < 0)
{
mpCaret->SetPosition(0,0); return;
}
case AccessibleTextType::WORD:
{
sal_Int32 nRemainingDistance (nDistance); while (nRemainingDistance != 0)
{
SharedPresenterTextParagraph pParagraph (GetParagraph(nParagraphIndex)); if (pParagraph)
{ const sal_Int32 nDelta (Signum(nDistance));
nCharacterIndex = pParagraph->GetWordBoundary(nCharacterIndex, nDelta); if (nCharacterIndex < 0)
{ // Go to previous or next paragraph.
nParagraphIndex += nDelta; if (nParagraphIndex < 0)
{
nParagraphIndex = 0;
nCharacterIndex = 0;
nRemainingDistance = 0;
} elseif (o3tl::make_unsigned(nParagraphIndex) >= maParagraphs.size())
{
nParagraphIndex = maParagraphs.size()-1;
pParagraph = GetParagraph(nParagraphIndex); if (pParagraph)
nCharacterIndex = pParagraph->GetCharacterCount();
nRemainingDistance = 0;
} else
{
nRemainingDistance -= nDelta;
// Move caret one character to the end of // the previous or the start of the next paragraph.
pParagraph = GetParagraph(nParagraphIndex); if (pParagraph)
{ if (nDistance<0)
nCharacterIndex = pParagraph->GetCharacterCount(); else
nCharacterIndex = 0;
}
}
} else
nRemainingDistance -= nDelta;
} else break;
} break;
}
}
// Move the caret to the new position.
mpCaret->SetPosition(nParagraphIndex, nCharacterIndex);
}
void PresenterTextView::Paint ( const css::awt::Rectangle& rUpdateBox)
{ if ( ! mxCanvas.is()) return; if ( ! mpFont->PrepareFont(mxCanvas)) return;
if (mbIsFormatPending)
Format();
// Setup the clipping rectangle. Horizontally we make it a little // larger to allow characters (and the caret) to stick out of their // bounding boxes. This can happen on some characters (like the // uppercase J) for typographical reasons. const sal_Int32 nAdditionalLeftBorder (10); const sal_Int32 nAdditionalRightBorder (5); double nX (maLocation.X - mnLeftOffset); double nY (maLocation.Y - mnTopOffset); const sal_Int32 nClipLeft (::std::max(
PresenterGeometryHelper::Round(maLocation.X)-nAdditionalLeftBorder, rUpdateBox.X)); const sal_Int32 nClipTop (::std::max(
PresenterGeometryHelper::Round(maLocation.Y), rUpdateBox.Y)); const sal_Int32 nClipRight (::std::min(
PresenterGeometryHelper::Round(maLocation.X+maSize.Width)+nAdditionalRightBorder, rUpdateBox.X+rUpdateBox.Width)); const sal_Int32 nClipBottom (::std::min(
PresenterGeometryHelper::Round(maLocation.Y+maSize.Height), rUpdateBox.Y+rUpdateBox.Height)); if (nClipLeft>=nClipRight || nClipTop>=nClipBottom) return;
if ( ! IsTextReferencePointLeft())
rRenderState.AffineTransform.m02 -= rSize.Width;
}
void PresenterTextParagraph::Format ( constdouble nY, constdouble nWidth, const PresenterTheme::SharedFontDescriptor& rpFont)
{ // Make sure that the text view is in a valid and sane state. if ( ! mxBreakIterator.is() || ! mxScriptTypeDetector.is()) return; if (nWidth<=0) return; if ( ! rpFont || ! rpFont->mxFont.is()) return;
// Remember the new word boundary for caret travelling by words. // Prevent duplicates. if (aWordBoundary.startPos > maWordBoundaries.back())
maWordBoundaries.push_back(aWordBoundary.startPos);
if (aWordBoundary.endPos>aWordBoundary.startPos)
AddWord(nWidth, aCurrentLine, aWordBoundary.endPos, rpFont);
if (aWordBoundary.startPos<0 || aWordBoundary.endPos<0) break; if (nPosition >= aWordBoundary.endPos) break;
nPosition = aWordBoundary.endPos;
}
if (aCurrentLine.endPos>aCurrentLine.startPos)
AddLine(aCurrentLine);
if (nLocalCharacterIndex < 0)
{ // The caller asked for the start or end position of the paragraph. if (nDistance < 0) return 0; else return GetCharacterCount();
}
sal_Int32 nIndex (0); for (sal_Int32 nCount (maWordBoundaries.size()); nIndex<nCount; ++nIndex)
{ if (maWordBoundaries[nIndex] >= nLocalCharacterIndex)
{ // When inside the word (not at its start or end) then // first move to the start or end before going the previous or // next word. if (maWordBoundaries[nIndex] > nLocalCharacterIndex) if (nDistance > 0)
--nIndex; break;
}
}
case AccessibleTextType::WORD: if (mxBreakIterator.is()) return GetWordTextSegment(nOffset, nIndex); break;
case AccessibleTextType::LINE:
{ auto iLine = std::find_if(maLines.begin(), maLines.end(),
[nIndex](const Line& rLine) { return nIndex < rLine.mnLineEndCharacterIndex; }); if (iLine != maLines.end())
{ return TextSegment(
msParagraphText.copy(
iLine->mnLineStartCharacterIndex,
iLine->mnLineEndCharacterIndex - iLine->mnLineStartCharacterIndex),
iLine->mnLineStartCharacterIndex,
iLine->mnLineEndCharacterIndex);
}
} break;
// Handle GLYPH and ATTRIBUTE_RUN like CHARACTER because we can not // do better at the moment. case AccessibleTextType::CHARACTER: case AccessibleTextType::GLYPH: case AccessibleTextType::ATTRIBUTE_RUN:
{ const sal_Int32 nStartIndex = nIndex + nOffset; const sal_Int32 nEndIndex = nStartIndex < GetCharacterCount() ? nStartIndex + 1 : nStartIndex; return CreateTextSegment(nStartIndex, nEndIndex);
}
}
awt::Rectangle PresenterTextParagraph::GetCharacterBounds (
sal_Int32 nGlobalCharacterIndex, constbool bCaretBox)
{ // Find the line that contains the requested character and accumulate // the previous line heights. double nX (mnXOrigin); double nY (mnYOrigin + mnVerticalOffset + mnAscent); const sal_Int8 nTextDirection (GetTextDirection()); for (sal_Int32 nLineIndex=0,nLineCount=maLines.size();
nLineIndex<nLineCount;
++nLineIndex, nY+=mnLineHeight)
{
Line& rLine (maLines[nLineIndex]); // Skip lines before the indexed character. if (nGlobalCharacterIndex >= rLine.mnLineEndCharacterIndex) // When in the last line then allow the index past the last char. if (nLineIndex<nLineCount-1) continue;
// The cell bounding box is defined relative to the origin of // the current line. Therefore we have to add the absolute // position of the line.
geometry::RealRectangle2D rCellBox (rLine.maCellBoxes[
::std::min(nCellIndex, rLine.maCellBoxes.getLength()-1)]);
// We are still here. That means that the given index lies past the // last character in the paragraph. // Return an empty box that lies past the last character. Better than nothing. return awt::Rectangle(sal_Int32(nX+0.5), sal_Int32(nY+0.5), 0, 0);
}
sal_Int8 PresenterTextParagraph::GetTextDirection() const
{ // Find first portion that has a non-neutral text direction.
sal_Int32 nPosition (0);
sal_Int32 nTextLength (msParagraphText.getLength()); while (nPosition < nTextLength)
{ const sal_Int16 nScriptDirection (
mxScriptTypeDetector->getScriptDirection(
msParagraphText, nPosition, i18n::ScriptDirection::NEUTRAL)); switch (nScriptDirection)
{ case i18n::ScriptDirection::NEUTRAL: // continue looping. break; case i18n::ScriptDirection::LEFT_TO_RIGHT: return rendering::TextDirection::WEAK_LEFT_TO_RIGHT;
case i18n::ScriptDirection::RIGHT_TO_LEFT: return rendering::TextDirection::WEAK_RIGHT_TO_LEFT;
}
// All text in paragraph is neutral. Fall back on writing mode taken // from the XText (which may not be properly initialized.)
sal_Int8 nTextDirection(rendering::TextDirection::WEAK_LEFT_TO_RIGHT); switch(mnWritingMode)
{ case text::WritingMode2::LR_TB:
nTextDirection = rendering::TextDirection::WEAK_LEFT_TO_RIGHT; break;
case text::WritingMode2::RL_TB:
nTextDirection = rendering::TextDirection::WEAK_RIGHT_TO_LEFT; break;
default: case text::WritingMode2::TB_RL: case text::WritingMode2::TB_LR: // Can not handle this. Use default and hope for the best. break;
} return nTextDirection;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.