1*c142477cSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*c142477cSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*c142477cSAndrew Rist * or more contributor license agreements. See the NOTICE file 5*c142477cSAndrew Rist * distributed with this work for additional information 6*c142477cSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*c142477cSAndrew Rist * to you under the Apache License, Version 2.0 (the 8*c142477cSAndrew Rist * "License"); you may not use this file except in compliance 9*c142477cSAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*c142477cSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*c142477cSAndrew Rist * Unless required by applicable law or agreed to in writing, 14*c142477cSAndrew Rist * software distributed under the License is distributed on an 15*c142477cSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*c142477cSAndrew Rist * KIND, either express or implied. See the License for the 17*c142477cSAndrew Rist * specific language governing permissions and limitations 18*c142477cSAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*c142477cSAndrew Rist *************************************************************/ 21*c142477cSAndrew Rist 22*c142477cSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir #include "precompiled_sdext.hxx" 25cdf0e10cSrcweir 26cdf0e10cSrcweir #include "PresenterTextView.hxx" 27cdf0e10cSrcweir #include "PresenterCanvasHelper.hxx" 28cdf0e10cSrcweir #include "PresenterGeometryHelper.hxx" 29cdf0e10cSrcweir #include "PresenterTimer.hxx" 30cdf0e10cSrcweir 31cdf0e10cSrcweir #include <cmath> 32cdf0e10cSrcweir 33cdf0e10cSrcweir #include <com/sun/star/accessibility/AccessibleTextType.hpp> 34cdf0e10cSrcweir #include <com/sun/star/container/XEnumerationAccess.hpp> 35cdf0e10cSrcweir #include <com/sun/star/i18n/CharType.hpp> 36cdf0e10cSrcweir #include <com/sun/star/i18n/CharacterIteratorMode.hpp> 37cdf0e10cSrcweir #include <com/sun/star/i18n/CTLScriptType.hpp> 38cdf0e10cSrcweir #include <com/sun/star/i18n/ScriptDirection.hpp> 39cdf0e10cSrcweir #include <com/sun/star/i18n/WordType.hpp> 40cdf0e10cSrcweir #include <com/sun/star/rendering/CompositeOperation.hpp> 41cdf0e10cSrcweir #include <com/sun/star/rendering/TextDirection.hpp> 42cdf0e10cSrcweir #include <com/sun/star/text/WritingMode2.hpp> 43cdf0e10cSrcweir #include <boost/bind.hpp> 44cdf0e10cSrcweir 45cdf0e10cSrcweir using namespace ::com::sun::star; 46cdf0e10cSrcweir using namespace ::com::sun::star::accessibility; 47cdf0e10cSrcweir using namespace ::com::sun::star::uno; 48cdf0e10cSrcweir 49cdf0e10cSrcweir #define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString))) 50cdf0e10cSrcweir 51cdf0e10cSrcweir const static sal_Int64 CaretBlinkIntervall = 500 * 1000 * 1000; 52cdf0e10cSrcweir 53cdf0e10cSrcweir //#define SHOW_CHARACTER_BOXES 54cdf0e10cSrcweir 55cdf0e10cSrcweir namespace { 56cdf0e10cSrcweir sal_Int32 Signum (const sal_Int32 nValue) 57cdf0e10cSrcweir { 58cdf0e10cSrcweir if (nValue < 0) 59cdf0e10cSrcweir return -1; 60cdf0e10cSrcweir else if (nValue > 0) 61cdf0e10cSrcweir return +1; 62cdf0e10cSrcweir else 63cdf0e10cSrcweir return 0; 64cdf0e10cSrcweir } 65cdf0e10cSrcweir } 66cdf0e10cSrcweir 67cdf0e10cSrcweir namespace sdext { namespace presenter { 68cdf0e10cSrcweir 69cdf0e10cSrcweir 70cdf0e10cSrcweir //===== PresenterTextView ===================================================== 71cdf0e10cSrcweir 72cdf0e10cSrcweir PresenterTextView::PresenterTextView ( 73cdf0e10cSrcweir const Reference<XComponentContext>& rxContext, 74cdf0e10cSrcweir const Reference<rendering::XCanvas>& rxCanvas, 75cdf0e10cSrcweir const ::boost::function<void(const ::css::awt::Rectangle&)>& rInvalidator) 76cdf0e10cSrcweir : mxCanvas(rxCanvas), 77cdf0e10cSrcweir mbDoOuput(true), 78cdf0e10cSrcweir mxBreakIterator(), 79cdf0e10cSrcweir mxScriptTypeDetector(), 80cdf0e10cSrcweir maLocation(0,0), 81cdf0e10cSrcweir maSize(0,0), 82cdf0e10cSrcweir mpFont(), 83cdf0e10cSrcweir maParagraphs(), 84cdf0e10cSrcweir mpCaret(new PresenterTextCaret( 85cdf0e10cSrcweir ::boost::bind(&PresenterTextView::GetCaretBounds, this, _1, _2), 86cdf0e10cSrcweir rInvalidator)), 87cdf0e10cSrcweir mnLeftOffset(0), 88cdf0e10cSrcweir mnTopOffset(0), 89cdf0e10cSrcweir maInvalidator(rInvalidator), 90cdf0e10cSrcweir mbIsFormatPending(false), 91cdf0e10cSrcweir mnCharacterCount(-1), 92cdf0e10cSrcweir maTextChangeBroadcaster() 93cdf0e10cSrcweir { 94cdf0e10cSrcweir Reference<lang::XMultiComponentFactory> xFactory ( 95cdf0e10cSrcweir rxContext->getServiceManager(), UNO_QUERY); 96cdf0e10cSrcweir if ( ! xFactory.is()) 97cdf0e10cSrcweir return; 98cdf0e10cSrcweir 99cdf0e10cSrcweir // Create the break iterator that we use to break text into lines. 100cdf0e10cSrcweir mxBreakIterator = Reference<i18n::XBreakIterator>( 101cdf0e10cSrcweir xFactory->createInstanceWithContext( 102cdf0e10cSrcweir A2S("com.sun.star.i18n.BreakIterator"), 103cdf0e10cSrcweir rxContext), 104cdf0e10cSrcweir UNO_QUERY_THROW); 105cdf0e10cSrcweir 106cdf0e10cSrcweir // Create the script type detector that is used to split paragraphs into 107cdf0e10cSrcweir // portions of the same text direction. 108cdf0e10cSrcweir mxScriptTypeDetector = Reference<i18n::XScriptTypeDetector>( 109cdf0e10cSrcweir xFactory->createInstanceWithContext( 110cdf0e10cSrcweir A2S("com.sun.star.i18n.ScriptTypeDetector"), 111cdf0e10cSrcweir rxContext), 112cdf0e10cSrcweir UNO_QUERY_THROW); 113cdf0e10cSrcweir } 114cdf0e10cSrcweir 115cdf0e10cSrcweir 116cdf0e10cSrcweir 117cdf0e10cSrcweir 118cdf0e10cSrcweir PresenterTextView::PresenterTextView ( 119cdf0e10cSrcweir const Reference<XComponentContext>& rxContext, 120cdf0e10cSrcweir const Reference<rendering::XCanvas>& rxCanvas) 121cdf0e10cSrcweir : mxCanvas(rxCanvas), 122cdf0e10cSrcweir mbDoOuput(false), 123cdf0e10cSrcweir mxBreakIterator(), 124cdf0e10cSrcweir mxScriptTypeDetector(), 125cdf0e10cSrcweir maLocation(0,0), 126cdf0e10cSrcweir maSize(0,0), 127cdf0e10cSrcweir mpFont(), 128cdf0e10cSrcweir maParagraphs(), 129cdf0e10cSrcweir mpCaret(new PresenterTextCaret( 130cdf0e10cSrcweir ::boost::bind(&PresenterTextView::GetCaretBounds, this, _1, _2), 131cdf0e10cSrcweir ::boost::function<void(const css::awt::Rectangle&)>())), 132cdf0e10cSrcweir mnLeftOffset(0), 133cdf0e10cSrcweir mnTopOffset(0), 134cdf0e10cSrcweir maInvalidator(), 135cdf0e10cSrcweir mbIsFormatPending(false), 136cdf0e10cSrcweir mnCharacterCount(-1), 137cdf0e10cSrcweir maTextChangeBroadcaster() 138cdf0e10cSrcweir { 139cdf0e10cSrcweir Reference<lang::XMultiComponentFactory> xFactory ( 140cdf0e10cSrcweir rxContext->getServiceManager(), UNO_QUERY); 141cdf0e10cSrcweir if ( ! xFactory.is()) 142cdf0e10cSrcweir return; 143cdf0e10cSrcweir 144cdf0e10cSrcweir // Create the break iterator that we use to break text into lines. 145cdf0e10cSrcweir mxBreakIterator = Reference<i18n::XBreakIterator>( 146cdf0e10cSrcweir xFactory->createInstanceWithContext( 147cdf0e10cSrcweir A2S("com.sun.star.i18n.BreakIterator"), 148cdf0e10cSrcweir rxContext), 149cdf0e10cSrcweir UNO_QUERY_THROW); 150cdf0e10cSrcweir 151cdf0e10cSrcweir // Create the script type detector that is used to split paragraphs into 152cdf0e10cSrcweir // portions of the same text direction. 153cdf0e10cSrcweir mxScriptTypeDetector = Reference<i18n::XScriptTypeDetector>( 154cdf0e10cSrcweir xFactory->createInstanceWithContext( 155cdf0e10cSrcweir A2S("com.sun.star.i18n.ScriptTypeDetector"), 156cdf0e10cSrcweir rxContext), 157cdf0e10cSrcweir UNO_QUERY_THROW); 158cdf0e10cSrcweir } 159cdf0e10cSrcweir 160cdf0e10cSrcweir 161cdf0e10cSrcweir 162cdf0e10cSrcweir 163cdf0e10cSrcweir void PresenterTextView::SetText (const Reference<text::XText>& rxText) 164cdf0e10cSrcweir { 165cdf0e10cSrcweir maParagraphs.clear(); 166cdf0e10cSrcweir mnCharacterCount = -1; 167cdf0e10cSrcweir 168cdf0e10cSrcweir Reference<container::XEnumerationAccess> xParagraphAccess (rxText, UNO_QUERY); 169cdf0e10cSrcweir if ( ! xParagraphAccess.is()) 170cdf0e10cSrcweir return; 171cdf0e10cSrcweir 172cdf0e10cSrcweir Reference<container::XEnumeration> xParagraphs ( 173cdf0e10cSrcweir xParagraphAccess->createEnumeration() , UNO_QUERY); 174cdf0e10cSrcweir if ( ! xParagraphs.is()) 175cdf0e10cSrcweir return; 176cdf0e10cSrcweir 177cdf0e10cSrcweir if ( ! mpFont || ! mpFont->PrepareFont(mxCanvas)) 178cdf0e10cSrcweir return; 179cdf0e10cSrcweir 180cdf0e10cSrcweir sal_Int32 nCharacterCount (0); 181cdf0e10cSrcweir while (xParagraphs->hasMoreElements()) 182cdf0e10cSrcweir { 183cdf0e10cSrcweir SharedPresenterTextParagraph pParagraph (new PresenterTextParagraph( 184cdf0e10cSrcweir maParagraphs.size(), 185cdf0e10cSrcweir mxBreakIterator, 186cdf0e10cSrcweir mxScriptTypeDetector, 187cdf0e10cSrcweir Reference<text::XTextRange>(xParagraphs->nextElement(), UNO_QUERY), 188cdf0e10cSrcweir mpCaret)); 189cdf0e10cSrcweir pParagraph->SetupCellArray(mpFont); 190cdf0e10cSrcweir pParagraph->SetCharacterOffset(nCharacterCount); 191cdf0e10cSrcweir nCharacterCount += pParagraph->GetCharacterCount(); 192cdf0e10cSrcweir maParagraphs.push_back(pParagraph); 193cdf0e10cSrcweir } 194cdf0e10cSrcweir 195cdf0e10cSrcweir if (mpCaret) 196cdf0e10cSrcweir mpCaret->HideCaret(); 197cdf0e10cSrcweir 198cdf0e10cSrcweir RequestFormat(); 199cdf0e10cSrcweir } 200cdf0e10cSrcweir 201cdf0e10cSrcweir 202cdf0e10cSrcweir 203cdf0e10cSrcweir 204cdf0e10cSrcweir void PresenterTextView::SetText (const ::rtl::OUString& rsText) 205cdf0e10cSrcweir { 206cdf0e10cSrcweir maParagraphs.clear(); 207cdf0e10cSrcweir mnCharacterCount = -1; 208cdf0e10cSrcweir 209cdf0e10cSrcweir if ( ! mpFont || ! mpFont->PrepareFont(mxCanvas)) 210cdf0e10cSrcweir return; 211cdf0e10cSrcweir 212cdf0e10cSrcweir sal_Int32 nCharacterCount (0); 213cdf0e10cSrcweir 214cdf0e10cSrcweir SharedPresenterTextParagraph pParagraph (new PresenterTextParagraph( 215cdf0e10cSrcweir 0, 216cdf0e10cSrcweir mxBreakIterator, 217cdf0e10cSrcweir mxScriptTypeDetector, 218cdf0e10cSrcweir rsText, 219cdf0e10cSrcweir mpCaret)); 220cdf0e10cSrcweir pParagraph->SetupCellArray(mpFont); 221cdf0e10cSrcweir pParagraph->SetCharacterOffset(nCharacterCount); 222cdf0e10cSrcweir nCharacterCount += pParagraph->GetCharacterCount(); 223cdf0e10cSrcweir maParagraphs.push_back(pParagraph); 224cdf0e10cSrcweir 225cdf0e10cSrcweir if (mpCaret) 226cdf0e10cSrcweir mpCaret->HideCaret(); 227cdf0e10cSrcweir 228cdf0e10cSrcweir RequestFormat(); 229cdf0e10cSrcweir } 230cdf0e10cSrcweir 231cdf0e10cSrcweir 232cdf0e10cSrcweir 233cdf0e10cSrcweir 234cdf0e10cSrcweir void PresenterTextView::SetTextChangeBroadcaster ( 235cdf0e10cSrcweir const ::boost::function<void(void)>& rBroadcaster) 236cdf0e10cSrcweir { 237cdf0e10cSrcweir maTextChangeBroadcaster = rBroadcaster; 238cdf0e10cSrcweir } 239cdf0e10cSrcweir 240cdf0e10cSrcweir 241cdf0e10cSrcweir 242cdf0e10cSrcweir 243cdf0e10cSrcweir void PresenterTextView::SetLocation (const css::geometry::RealPoint2D& rLocation) 244cdf0e10cSrcweir { 245cdf0e10cSrcweir maLocation = rLocation; 246cdf0e10cSrcweir 247cdf0e10cSrcweir for (::std::vector<SharedPresenterTextParagraph>::iterator 248cdf0e10cSrcweir iParagraph(maParagraphs.begin()), 249cdf0e10cSrcweir iEnd(maParagraphs.end()); 250cdf0e10cSrcweir iParagraph!=iEnd; 251cdf0e10cSrcweir ++iParagraph) 252cdf0e10cSrcweir { 253cdf0e10cSrcweir (*iParagraph)->SetOrigin( 254cdf0e10cSrcweir maLocation.X - mnLeftOffset, 255cdf0e10cSrcweir maLocation.Y - mnTopOffset); 256cdf0e10cSrcweir } 257cdf0e10cSrcweir } 258cdf0e10cSrcweir 259cdf0e10cSrcweir 260cdf0e10cSrcweir 261cdf0e10cSrcweir 262cdf0e10cSrcweir void PresenterTextView::SetSize (const css::geometry::RealSize2D& rSize) 263cdf0e10cSrcweir { 264cdf0e10cSrcweir maSize = rSize; 265cdf0e10cSrcweir RequestFormat(); 266cdf0e10cSrcweir } 267cdf0e10cSrcweir 268cdf0e10cSrcweir 269cdf0e10cSrcweir 270cdf0e10cSrcweir 271cdf0e10cSrcweir double PresenterTextView::GetTotalTextHeight (void) 272cdf0e10cSrcweir { 273cdf0e10cSrcweir double nTotalHeight (0); 274cdf0e10cSrcweir 275cdf0e10cSrcweir if (mbIsFormatPending) 276cdf0e10cSrcweir { 277cdf0e10cSrcweir if ( ! mpFont->PrepareFont(mxCanvas)) 278cdf0e10cSrcweir return 0; 279cdf0e10cSrcweir Format(); 280cdf0e10cSrcweir } 281cdf0e10cSrcweir 282cdf0e10cSrcweir for (::std::vector<SharedPresenterTextParagraph>::iterator 283cdf0e10cSrcweir iParagraph(maParagraphs.begin()), 284cdf0e10cSrcweir iEnd(maParagraphs.end()); 285cdf0e10cSrcweir iParagraph!=iEnd; 286cdf0e10cSrcweir ++iParagraph) 287cdf0e10cSrcweir { 288cdf0e10cSrcweir nTotalHeight += (*iParagraph)->GetTotalTextHeight(); 289cdf0e10cSrcweir } 290cdf0e10cSrcweir 291cdf0e10cSrcweir return nTotalHeight; 292cdf0e10cSrcweir } 293cdf0e10cSrcweir 294cdf0e10cSrcweir 295cdf0e10cSrcweir 296cdf0e10cSrcweir 297cdf0e10cSrcweir void PresenterTextView::SetFont (const PresenterTheme::SharedFontDescriptor& rpFont) 298cdf0e10cSrcweir { 299cdf0e10cSrcweir mpFont = rpFont; 300cdf0e10cSrcweir RequestFormat(); 301cdf0e10cSrcweir } 302cdf0e10cSrcweir 303cdf0e10cSrcweir 304cdf0e10cSrcweir 305cdf0e10cSrcweir 306cdf0e10cSrcweir void PresenterTextView::SetOffset( 307cdf0e10cSrcweir const double nLeft, 308cdf0e10cSrcweir const double nTop) 309cdf0e10cSrcweir { 310cdf0e10cSrcweir mnLeftOffset = nLeft; 311cdf0e10cSrcweir mnTopOffset = nTop; 312cdf0e10cSrcweir 313cdf0e10cSrcweir // Trigger an update of the text origin stored at the individual paragraphs. 314cdf0e10cSrcweir SetLocation(maLocation); 315cdf0e10cSrcweir } 316cdf0e10cSrcweir 317cdf0e10cSrcweir 318cdf0e10cSrcweir 319cdf0e10cSrcweir void PresenterTextView::MoveCaret ( 320cdf0e10cSrcweir const sal_Int32 nDistance, 321cdf0e10cSrcweir const sal_Int16 nTextType) 322cdf0e10cSrcweir { 323cdf0e10cSrcweir if ( ! mpCaret) 324cdf0e10cSrcweir return; 325cdf0e10cSrcweir 326cdf0e10cSrcweir // When the caret has not been visible yet then move it to the beginning 327cdf0e10cSrcweir // of the text. 328cdf0e10cSrcweir if (mpCaret->GetParagraphIndex() < 0) 329cdf0e10cSrcweir { 330cdf0e10cSrcweir mpCaret->SetPosition(0,0); 331cdf0e10cSrcweir return; 332cdf0e10cSrcweir } 333cdf0e10cSrcweir 334cdf0e10cSrcweir sal_Int32 nParagraphIndex (mpCaret->GetParagraphIndex()); 335cdf0e10cSrcweir sal_Int32 nCharacterIndex (mpCaret->GetCharacterIndex()); 336cdf0e10cSrcweir switch (nTextType) 337cdf0e10cSrcweir { 338cdf0e10cSrcweir default: 339cdf0e10cSrcweir case AccessibleTextType::CHARACTER: 340cdf0e10cSrcweir nCharacterIndex += nDistance; 341cdf0e10cSrcweir break; 342cdf0e10cSrcweir 343cdf0e10cSrcweir case AccessibleTextType::WORD: 344cdf0e10cSrcweir { 345cdf0e10cSrcweir sal_Int32 nRemainingDistance (nDistance); 346cdf0e10cSrcweir while (nRemainingDistance != 0) 347cdf0e10cSrcweir { 348cdf0e10cSrcweir SharedPresenterTextParagraph pParagraph (GetParagraph(nParagraphIndex)); 349cdf0e10cSrcweir if (pParagraph) 350cdf0e10cSrcweir { 351cdf0e10cSrcweir const sal_Int32 nDelta (Signum(nDistance)); 352cdf0e10cSrcweir nCharacterIndex = pParagraph->GetWordBoundary(nCharacterIndex, nDelta); 353cdf0e10cSrcweir if (nCharacterIndex < 0) 354cdf0e10cSrcweir { 355cdf0e10cSrcweir // Go to previous or next paragraph. 356cdf0e10cSrcweir nParagraphIndex += nDelta; 357cdf0e10cSrcweir if (nParagraphIndex < 0) 358cdf0e10cSrcweir { 359cdf0e10cSrcweir nParagraphIndex = 0; 360cdf0e10cSrcweir nCharacterIndex = 0; 361cdf0e10cSrcweir nRemainingDistance = 0; 362cdf0e10cSrcweir } 363cdf0e10cSrcweir else if (sal_uInt32(nParagraphIndex) >= maParagraphs.size()) 364cdf0e10cSrcweir { 365cdf0e10cSrcweir nParagraphIndex = maParagraphs.size()-1; 366cdf0e10cSrcweir pParagraph = GetParagraph(nParagraphIndex); 367cdf0e10cSrcweir if (pParagraph) 368cdf0e10cSrcweir nCharacterIndex = pParagraph->GetCharacterCount(); 369cdf0e10cSrcweir nRemainingDistance = 0; 370cdf0e10cSrcweir } 371cdf0e10cSrcweir else 372cdf0e10cSrcweir { 373cdf0e10cSrcweir nRemainingDistance -= nDelta; 374cdf0e10cSrcweir 375cdf0e10cSrcweir // Move caret one character to the end of 376cdf0e10cSrcweir // the previous or the start of the next paragraph. 377cdf0e10cSrcweir pParagraph = GetParagraph(nParagraphIndex); 378cdf0e10cSrcweir if (pParagraph) 379cdf0e10cSrcweir { 380cdf0e10cSrcweir if (nDistance<0) 381cdf0e10cSrcweir nCharacterIndex = pParagraph->GetCharacterCount(); 382cdf0e10cSrcweir else 383cdf0e10cSrcweir nCharacterIndex = 0; 384cdf0e10cSrcweir } 385cdf0e10cSrcweir } 386cdf0e10cSrcweir } 387cdf0e10cSrcweir else 388cdf0e10cSrcweir nRemainingDistance -= nDelta; 389cdf0e10cSrcweir } 390cdf0e10cSrcweir else 391cdf0e10cSrcweir break; 392cdf0e10cSrcweir } 393cdf0e10cSrcweir break; 394cdf0e10cSrcweir } 395cdf0e10cSrcweir } 396cdf0e10cSrcweir 397cdf0e10cSrcweir // Move the caret to the new position. 398cdf0e10cSrcweir mpCaret->SetPosition(nParagraphIndex, nCharacterIndex); 399cdf0e10cSrcweir } 400cdf0e10cSrcweir 401cdf0e10cSrcweir 402cdf0e10cSrcweir 403cdf0e10cSrcweir 404cdf0e10cSrcweir void PresenterTextView::Paint ( 405cdf0e10cSrcweir const css::awt::Rectangle& rUpdateBox) 406cdf0e10cSrcweir { 407cdf0e10cSrcweir if ( ! mbDoOuput) 408cdf0e10cSrcweir return; 409cdf0e10cSrcweir if ( ! mxCanvas.is()) 410cdf0e10cSrcweir return; 411cdf0e10cSrcweir if ( ! mpFont->PrepareFont(mxCanvas)) 412cdf0e10cSrcweir return; 413cdf0e10cSrcweir 414cdf0e10cSrcweir if (mbIsFormatPending) 415cdf0e10cSrcweir Format(); 416cdf0e10cSrcweir 417cdf0e10cSrcweir // Setup the clipping rectangle. Horizontally we make it a little 418cdf0e10cSrcweir // larger to allow characters (and the caret) to stick out of their 419cdf0e10cSrcweir // bounding boxes. This can happen on some characters (like the 420cdf0e10cSrcweir // uppercase J) for typographical reasons. 421cdf0e10cSrcweir const sal_Int32 nAdditionalLeftBorder (10); 422cdf0e10cSrcweir const sal_Int32 nAdditionalRightBorder (5); 423cdf0e10cSrcweir double nX (maLocation.X - mnLeftOffset); 424cdf0e10cSrcweir double nY (maLocation.Y - mnTopOffset); 425cdf0e10cSrcweir const sal_Int32 nClipLeft (::std::max( 426cdf0e10cSrcweir PresenterGeometryHelper::Round(maLocation.X)-nAdditionalLeftBorder, rUpdateBox.X)); 427cdf0e10cSrcweir const sal_Int32 nClipTop (::std::max( 428cdf0e10cSrcweir PresenterGeometryHelper::Round(maLocation.Y), rUpdateBox.Y)); 429cdf0e10cSrcweir const sal_Int32 nClipRight (::std::min( 430cdf0e10cSrcweir PresenterGeometryHelper::Round(maLocation.X+maSize.Width)+nAdditionalRightBorder, rUpdateBox.X+rUpdateBox.Width)); 431cdf0e10cSrcweir const sal_Int32 nClipBottom (::std::min( 432cdf0e10cSrcweir PresenterGeometryHelper::Round(maLocation.Y+maSize.Height), rUpdateBox.Y+rUpdateBox.Height)); 433cdf0e10cSrcweir if (nClipLeft>=nClipRight || nClipTop>=nClipBottom) 434cdf0e10cSrcweir return; 435cdf0e10cSrcweir 436cdf0e10cSrcweir const awt::Rectangle aClipBox( 437cdf0e10cSrcweir nClipLeft, 438cdf0e10cSrcweir nClipTop, 439cdf0e10cSrcweir nClipRight - nClipLeft, 440cdf0e10cSrcweir nClipBottom - nClipTop); 441cdf0e10cSrcweir Reference<rendering::XPolyPolygon2D> xClipPolygon ( 442cdf0e10cSrcweir PresenterGeometryHelper::CreatePolygon(aClipBox, mxCanvas->getDevice())); 443cdf0e10cSrcweir 444cdf0e10cSrcweir const rendering::ViewState aViewState( 445cdf0e10cSrcweir geometry::AffineMatrix2D(1,0,0, 0,1,0), 446cdf0e10cSrcweir xClipPolygon); 447cdf0e10cSrcweir 448cdf0e10cSrcweir rendering::RenderState aRenderState ( 449cdf0e10cSrcweir geometry::AffineMatrix2D(1,0,nX, 0,1,nY), 450cdf0e10cSrcweir NULL, 451cdf0e10cSrcweir Sequence<double>(4), 452cdf0e10cSrcweir rendering::CompositeOperation::SOURCE); 453cdf0e10cSrcweir PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor); 454cdf0e10cSrcweir 455cdf0e10cSrcweir for (::std::vector<SharedPresenterTextParagraph>::const_iterator 456cdf0e10cSrcweir iParagraph(maParagraphs.begin()), 457cdf0e10cSrcweir iEnd(maParagraphs.end()); 458cdf0e10cSrcweir iParagraph!=iEnd; 459cdf0e10cSrcweir ++iParagraph) 460cdf0e10cSrcweir { 461cdf0e10cSrcweir (*iParagraph)->Paint( 462cdf0e10cSrcweir mxCanvas, 463cdf0e10cSrcweir maSize, 464cdf0e10cSrcweir mpFont, 465cdf0e10cSrcweir aViewState, 466cdf0e10cSrcweir aRenderState, 467cdf0e10cSrcweir mnTopOffset, 468cdf0e10cSrcweir nClipTop, 469cdf0e10cSrcweir nClipBottom); 470cdf0e10cSrcweir } 471cdf0e10cSrcweir 472cdf0e10cSrcweir aRenderState.AffineTransform.m02 = 0; 473cdf0e10cSrcweir aRenderState.AffineTransform.m12 = 0; 474cdf0e10cSrcweir 475cdf0e10cSrcweir #ifdef SHOW_CHARACTER_BOXES 476cdf0e10cSrcweir PresenterCanvasHelper::SetDeviceColor(aRenderState, 0x00808080); 477cdf0e10cSrcweir for (sal_Int32 nParagraphIndex(0), nParagraphCount(GetParagraphCount()); 478cdf0e10cSrcweir nParagraphIndex<nParagraphCount; 479cdf0e10cSrcweir ++nParagraphIndex) 480cdf0e10cSrcweir { 481cdf0e10cSrcweir const SharedPresenterTextParagraph pParagraph (GetParagraph(nParagraphIndex)); 482cdf0e10cSrcweir if ( ! pParagraph) 483cdf0e10cSrcweir continue; 484cdf0e10cSrcweir for (sal_Int32 nCharacterIndex(0),nCharacterCount(pParagraph->GetCharacterCount()); 485cdf0e10cSrcweir nCharacterIndex<nCharacterCount; ++nCharacterIndex) 486cdf0e10cSrcweir { 487cdf0e10cSrcweir const awt::Rectangle aBox (pParagraph->GetCharacterBounds(nCharacterIndex, false)); 488cdf0e10cSrcweir mxCanvas->drawPolyPolygon ( 489cdf0e10cSrcweir PresenterGeometryHelper::CreatePolygon( 490cdf0e10cSrcweir aBox, 491cdf0e10cSrcweir mxCanvas->getDevice()), 492cdf0e10cSrcweir aViewState, 493cdf0e10cSrcweir aRenderState); 494cdf0e10cSrcweir } 495cdf0e10cSrcweir } 496cdf0e10cSrcweir PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor); 497cdf0e10cSrcweir #endif 498cdf0e10cSrcweir 499cdf0e10cSrcweir if (mpCaret && mpCaret->IsVisible()) 500cdf0e10cSrcweir { 501cdf0e10cSrcweir mxCanvas->fillPolyPolygon ( 502cdf0e10cSrcweir PresenterGeometryHelper::CreatePolygon( 503cdf0e10cSrcweir mpCaret->GetBounds(), 504cdf0e10cSrcweir mxCanvas->getDevice()), 505cdf0e10cSrcweir aViewState, 506cdf0e10cSrcweir aRenderState); 507cdf0e10cSrcweir } 508cdf0e10cSrcweir } 509cdf0e10cSrcweir 510cdf0e10cSrcweir 511cdf0e10cSrcweir 512cdf0e10cSrcweir 513cdf0e10cSrcweir SharedPresenterTextCaret PresenterTextView::GetCaret (void) const 514cdf0e10cSrcweir { 515cdf0e10cSrcweir return mpCaret; 516cdf0e10cSrcweir } 517cdf0e10cSrcweir 518cdf0e10cSrcweir 519cdf0e10cSrcweir 520cdf0e10cSrcweir 521cdf0e10cSrcweir sal_Int32 PresenterTextView::GetCharacterOffset (const sal_Int32 nParagraphIndex) const 522cdf0e10cSrcweir { 523cdf0e10cSrcweir sal_Int32 nCharacterOffset (0); 524cdf0e10cSrcweir for (sal_Int32 nIndex=0; nIndex<nParagraphIndex; ++nIndex) 525cdf0e10cSrcweir nCharacterOffset += maParagraphs[nIndex]->GetCharacterCount(); 526cdf0e10cSrcweir return nCharacterOffset; 527cdf0e10cSrcweir } 528cdf0e10cSrcweir 529cdf0e10cSrcweir 530cdf0e10cSrcweir 531cdf0e10cSrcweir 532cdf0e10cSrcweir awt::Rectangle PresenterTextView::GetCaretBounds ( 533cdf0e10cSrcweir sal_Int32 nParagraphIndex, 534cdf0e10cSrcweir const sal_Int32 nCharacterIndex) const 535cdf0e10cSrcweir { 536cdf0e10cSrcweir SharedPresenterTextParagraph pParagraph (GetParagraph(nParagraphIndex)); 537cdf0e10cSrcweir 538cdf0e10cSrcweir if (pParagraph) 539cdf0e10cSrcweir return pParagraph->GetCharacterBounds(nCharacterIndex, true); 540cdf0e10cSrcweir else 541cdf0e10cSrcweir return awt::Rectangle(0,0,0,0); 542cdf0e10cSrcweir } 543cdf0e10cSrcweir 544cdf0e10cSrcweir 545cdf0e10cSrcweir 546cdf0e10cSrcweir 547cdf0e10cSrcweir //----- private --------------------------------------------------------------- 548cdf0e10cSrcweir 549cdf0e10cSrcweir void PresenterTextView::RequestFormat (void) 550cdf0e10cSrcweir { 551cdf0e10cSrcweir mbIsFormatPending = true; 552cdf0e10cSrcweir } 553cdf0e10cSrcweir 554cdf0e10cSrcweir 555cdf0e10cSrcweir 556cdf0e10cSrcweir 557cdf0e10cSrcweir void PresenterTextView::Format (void) 558cdf0e10cSrcweir { 559cdf0e10cSrcweir mbIsFormatPending = false; 560cdf0e10cSrcweir 561cdf0e10cSrcweir double nY (0); 562cdf0e10cSrcweir for (::std::vector<SharedPresenterTextParagraph>::const_iterator 563cdf0e10cSrcweir iParagraph(maParagraphs.begin()), 564cdf0e10cSrcweir iEnd(maParagraphs.end()); 565cdf0e10cSrcweir iParagraph!=iEnd; 566cdf0e10cSrcweir ++iParagraph) 567cdf0e10cSrcweir { 568cdf0e10cSrcweir (*iParagraph)->Format(nY, maSize.Width, mpFont); 569cdf0e10cSrcweir nY += (*iParagraph)->GetTotalTextHeight(); 570cdf0e10cSrcweir } 571cdf0e10cSrcweir 572cdf0e10cSrcweir if (maTextChangeBroadcaster) 573cdf0e10cSrcweir maTextChangeBroadcaster(); 574cdf0e10cSrcweir } 575cdf0e10cSrcweir 576cdf0e10cSrcweir 577cdf0e10cSrcweir 578cdf0e10cSrcweir 579cdf0e10cSrcweir sal_Int32 PresenterTextView::GetParagraphCount (void) const 580cdf0e10cSrcweir { 581cdf0e10cSrcweir return maParagraphs.size(); 582cdf0e10cSrcweir } 583cdf0e10cSrcweir 584cdf0e10cSrcweir 585cdf0e10cSrcweir 586cdf0e10cSrcweir 587cdf0e10cSrcweir SharedPresenterTextParagraph PresenterTextView::GetParagraph ( 588cdf0e10cSrcweir const sal_Int32 nParagraphIndex) const 589cdf0e10cSrcweir { 590cdf0e10cSrcweir if (nParagraphIndex < 0) 591cdf0e10cSrcweir return SharedPresenterTextParagraph(); 592cdf0e10cSrcweir else if (nParagraphIndex>=sal_Int32(maParagraphs.size())) 593cdf0e10cSrcweir return SharedPresenterTextParagraph(); 594cdf0e10cSrcweir else 595cdf0e10cSrcweir return maParagraphs[nParagraphIndex]; 596cdf0e10cSrcweir } 597cdf0e10cSrcweir 598cdf0e10cSrcweir 599cdf0e10cSrcweir 600cdf0e10cSrcweir 601cdf0e10cSrcweir //===== PresenterTextParagraph ================================================ 602cdf0e10cSrcweir 603cdf0e10cSrcweir PresenterTextParagraph::PresenterTextParagraph ( 604cdf0e10cSrcweir const sal_Int32 nParagraphIndex, 605cdf0e10cSrcweir const Reference<i18n::XBreakIterator>& rxBreakIterator, 606cdf0e10cSrcweir const Reference<i18n::XScriptTypeDetector>& rxScriptTypeDetector, 607cdf0e10cSrcweir const Reference<text::XTextRange>& rxTextRange, 608cdf0e10cSrcweir const SharedPresenterTextCaret& rpCaret) 609cdf0e10cSrcweir : msParagraphText(), 610cdf0e10cSrcweir mnParagraphIndex(nParagraphIndex), 611cdf0e10cSrcweir mpCaret(rpCaret), 612cdf0e10cSrcweir mxBreakIterator(rxBreakIterator), 613cdf0e10cSrcweir mxScriptTypeDetector(rxScriptTypeDetector), 614cdf0e10cSrcweir maLines(), 615cdf0e10cSrcweir mnVerticalOffset(0), 616cdf0e10cSrcweir mnXOrigin(0), 617cdf0e10cSrcweir mnYOrigin(0), 618cdf0e10cSrcweir mnWidth(0), 619cdf0e10cSrcweir mnAscent(0), 620cdf0e10cSrcweir mnDescent(0), 621cdf0e10cSrcweir mnLineHeight(-1), 622cdf0e10cSrcweir meAdjust(style::ParagraphAdjust_LEFT), 623cdf0e10cSrcweir mnWritingMode (text::WritingMode2::LR_TB), 624cdf0e10cSrcweir mnCharacterOffset(0), 625cdf0e10cSrcweir maCells() 626cdf0e10cSrcweir { 627cdf0e10cSrcweir if (rxTextRange.is()) 628cdf0e10cSrcweir { 629cdf0e10cSrcweir Reference<beans::XPropertySet> xProperties (rxTextRange, UNO_QUERY); 630cdf0e10cSrcweir lang::Locale aLocale; 631cdf0e10cSrcweir try 632cdf0e10cSrcweir { 633cdf0e10cSrcweir xProperties->getPropertyValue(A2S("CharLocale")) >>= aLocale; 634cdf0e10cSrcweir } 635cdf0e10cSrcweir catch(beans::UnknownPropertyException&) 636cdf0e10cSrcweir { 637cdf0e10cSrcweir // Ignore the exception. Use the default value. 638cdf0e10cSrcweir } 639cdf0e10cSrcweir try 640cdf0e10cSrcweir { 641cdf0e10cSrcweir xProperties->getPropertyValue(A2S("ParaAdjust")) >>= meAdjust; 642cdf0e10cSrcweir } 643cdf0e10cSrcweir catch(beans::UnknownPropertyException&) 644cdf0e10cSrcweir { 645cdf0e10cSrcweir // Ignore the exception. Use the default value. 646cdf0e10cSrcweir } 647cdf0e10cSrcweir try 648cdf0e10cSrcweir { 649cdf0e10cSrcweir xProperties->getPropertyValue(A2S("WritingMode")) >>= mnWritingMode; 650cdf0e10cSrcweir } 651cdf0e10cSrcweir catch(beans::UnknownPropertyException&) 652cdf0e10cSrcweir { 653cdf0e10cSrcweir // Ignore the exception. Use the default value. 654cdf0e10cSrcweir } 655cdf0e10cSrcweir 656cdf0e10cSrcweir msParagraphText = rxTextRange->getString(); 657cdf0e10cSrcweir } 658cdf0e10cSrcweir } 659cdf0e10cSrcweir 660cdf0e10cSrcweir 661cdf0e10cSrcweir 662cdf0e10cSrcweir 663cdf0e10cSrcweir PresenterTextParagraph::PresenterTextParagraph ( 664cdf0e10cSrcweir const sal_Int32 nParagraphIndex, 665cdf0e10cSrcweir const Reference<i18n::XBreakIterator>& rxBreakIterator, 666cdf0e10cSrcweir const Reference<i18n::XScriptTypeDetector>& rxScriptTypeDetector, 667cdf0e10cSrcweir const ::rtl::OUString& rsText, 668cdf0e10cSrcweir const SharedPresenterTextCaret& rpCaret) 669cdf0e10cSrcweir : msParagraphText(rsText), 670cdf0e10cSrcweir mnParagraphIndex(nParagraphIndex), 671cdf0e10cSrcweir mpCaret(rpCaret), 672cdf0e10cSrcweir mxBreakIterator(rxBreakIterator), 673cdf0e10cSrcweir mxScriptTypeDetector(rxScriptTypeDetector), 674cdf0e10cSrcweir maLines(), 675cdf0e10cSrcweir mnVerticalOffset(0), 676cdf0e10cSrcweir mnXOrigin(0), 677cdf0e10cSrcweir mnYOrigin(0), 678cdf0e10cSrcweir mnWidth(0), 679cdf0e10cSrcweir mnAscent(0), 680cdf0e10cSrcweir mnDescent(0), 681cdf0e10cSrcweir mnLineHeight(-1), 682cdf0e10cSrcweir meAdjust(style::ParagraphAdjust_LEFT), 683cdf0e10cSrcweir mnWritingMode (text::WritingMode2::LR_TB), 684cdf0e10cSrcweir mnCharacterOffset(0), 685cdf0e10cSrcweir maCells() 686cdf0e10cSrcweir { 687cdf0e10cSrcweir } 688cdf0e10cSrcweir 689cdf0e10cSrcweir 690cdf0e10cSrcweir 691cdf0e10cSrcweir 692cdf0e10cSrcweir void PresenterTextParagraph::Paint ( 693cdf0e10cSrcweir const Reference<rendering::XCanvas>& rxCanvas, 694cdf0e10cSrcweir const geometry::RealSize2D& rSize, 695cdf0e10cSrcweir const PresenterTheme::SharedFontDescriptor& rpFont, 696cdf0e10cSrcweir const rendering::ViewState& rViewState, 697cdf0e10cSrcweir rendering::RenderState& rRenderState, 698cdf0e10cSrcweir const double nTopOffset, 699cdf0e10cSrcweir const double nClipTop, 700cdf0e10cSrcweir const double nClipBottom) 701cdf0e10cSrcweir { 702cdf0e10cSrcweir if (mnLineHeight <= 0) 703cdf0e10cSrcweir return; 704cdf0e10cSrcweir 705cdf0e10cSrcweir sal_Int8 nTextDirection (GetTextDirection()); 706cdf0e10cSrcweir 707cdf0e10cSrcweir const double nSavedM12 (rRenderState.AffineTransform.m12); 708cdf0e10cSrcweir 709cdf0e10cSrcweir if ( ! IsTextReferencePointLeft()) 710cdf0e10cSrcweir rRenderState.AffineTransform.m02 += rSize.Width; 711cdf0e10cSrcweir 712cdf0e10cSrcweir 713cdf0e10cSrcweir #ifdef SHOW_CHARACTER_BOXES 714cdf0e10cSrcweir for (sal_Int32 nIndex=0,nCount=maLines.size(); 715cdf0e10cSrcweir nIndex<nCount; 716cdf0e10cSrcweir ++nIndex) 717cdf0e10cSrcweir { 718cdf0e10cSrcweir Line& rLine (maLines[nIndex]); 719cdf0e10cSrcweir rLine.ProvideLayoutedLine(msParagraphText, rpFont, nTextDirection); 720cdf0e10cSrcweir } 721cdf0e10cSrcweir #endif 722cdf0e10cSrcweir 723cdf0e10cSrcweir for (sal_Int32 nIndex=0,nCount=maLines.size(); 724cdf0e10cSrcweir nIndex<nCount; 725cdf0e10cSrcweir ++nIndex, rRenderState.AffineTransform.m12 += mnLineHeight) 726cdf0e10cSrcweir { 727cdf0e10cSrcweir Line& rLine (maLines[nIndex]); 728cdf0e10cSrcweir 729cdf0e10cSrcweir // Paint only visible lines. 730cdf0e10cSrcweir const double nLineTop = rLine.mnBaseLine - mnAscent - nTopOffset; 731cdf0e10cSrcweir if (nLineTop + mnLineHeight< nClipTop) 732cdf0e10cSrcweir continue; 733cdf0e10cSrcweir else if (nLineTop > nClipBottom) 734cdf0e10cSrcweir break; 735cdf0e10cSrcweir rLine.ProvideLayoutedLine(msParagraphText, rpFont, nTextDirection); 736cdf0e10cSrcweir 737cdf0e10cSrcweir rRenderState.AffineTransform.m12 = nSavedM12 + rLine.mnBaseLine; 738cdf0e10cSrcweir 739cdf0e10cSrcweir rxCanvas->drawTextLayout ( 740cdf0e10cSrcweir rLine.mxLayoutedLine, 741cdf0e10cSrcweir rViewState, 742cdf0e10cSrcweir rRenderState); 743cdf0e10cSrcweir } 744cdf0e10cSrcweir rRenderState.AffineTransform.m12 = nSavedM12; 745cdf0e10cSrcweir 746cdf0e10cSrcweir if ( ! IsTextReferencePointLeft()) 747cdf0e10cSrcweir rRenderState.AffineTransform.m02 -= rSize.Width; 748cdf0e10cSrcweir } 749cdf0e10cSrcweir 750cdf0e10cSrcweir 751cdf0e10cSrcweir 752cdf0e10cSrcweir 753cdf0e10cSrcweir void PresenterTextParagraph::Format ( 754cdf0e10cSrcweir const double nY, 755cdf0e10cSrcweir const double nWidth, 756cdf0e10cSrcweir const PresenterTheme::SharedFontDescriptor& rpFont) 757cdf0e10cSrcweir { 758cdf0e10cSrcweir // Make sure that the text view is in a valid and sane state. 759cdf0e10cSrcweir if ( ! mxBreakIterator.is() || ! mxScriptTypeDetector.is()) 760cdf0e10cSrcweir return; 761cdf0e10cSrcweir if (nWidth<=0) 762cdf0e10cSrcweir return; 763cdf0e10cSrcweir if ( ! rpFont || ! rpFont->mxFont.is()) 764cdf0e10cSrcweir return; 765cdf0e10cSrcweir 766cdf0e10cSrcweir sal_Int32 nPosition (0); 767cdf0e10cSrcweir 768cdf0e10cSrcweir mnWidth = nWidth; 769cdf0e10cSrcweir maLines.clear(); 770cdf0e10cSrcweir mnLineHeight = 0; 771cdf0e10cSrcweir mnAscent = 0; 772cdf0e10cSrcweir mnDescent = 0; 773cdf0e10cSrcweir mnVerticalOffset = nY; 774cdf0e10cSrcweir maWordBoundaries.clear(); 775cdf0e10cSrcweir maWordBoundaries.push_back(0); 776cdf0e10cSrcweir 777cdf0e10cSrcweir const rendering::FontMetrics aMetrics (rpFont->mxFont->getFontMetrics()); 778cdf0e10cSrcweir mnAscent = aMetrics.Ascent; 779cdf0e10cSrcweir mnDescent = aMetrics.Descent; 780cdf0e10cSrcweir mnLineHeight = aMetrics.Ascent + aMetrics.Descent + aMetrics.ExternalLeading; 781cdf0e10cSrcweir nPosition = 0; 782cdf0e10cSrcweir i18n::Boundary aCurrentLine(0,0); 783cdf0e10cSrcweir while (true) 784cdf0e10cSrcweir { 785cdf0e10cSrcweir const i18n::Boundary aWordBoundary = mxBreakIterator->nextWord( 786cdf0e10cSrcweir msParagraphText, 787cdf0e10cSrcweir nPosition, 788cdf0e10cSrcweir lang::Locale(), 789cdf0e10cSrcweir i18n::WordType::ANYWORD_IGNOREWHITESPACES); 790cdf0e10cSrcweir AddWord(nWidth, aCurrentLine, aWordBoundary.startPos, rpFont); 791cdf0e10cSrcweir 792cdf0e10cSrcweir // Remember the new word boundary for caret travelling by words. 793cdf0e10cSrcweir // Prevent duplicates. 794cdf0e10cSrcweir if (aWordBoundary.startPos > maWordBoundaries.back()) 795cdf0e10cSrcweir maWordBoundaries.push_back(aWordBoundary.startPos); 796cdf0e10cSrcweir 797cdf0e10cSrcweir if (aWordBoundary.endPos>aWordBoundary.startPos) 798cdf0e10cSrcweir AddWord(nWidth, aCurrentLine, aWordBoundary.endPos, rpFont); 799cdf0e10cSrcweir 800cdf0e10cSrcweir if (aWordBoundary.startPos<0 || aWordBoundary.endPos<0) 801cdf0e10cSrcweir break; 802cdf0e10cSrcweir if (nPosition >= aWordBoundary.endPos) 803cdf0e10cSrcweir break; 804cdf0e10cSrcweir nPosition = aWordBoundary.endPos; 805cdf0e10cSrcweir } 806cdf0e10cSrcweir 807cdf0e10cSrcweir if (aCurrentLine.endPos>aCurrentLine.startPos) 808cdf0e10cSrcweir AddLine(aCurrentLine); 809cdf0e10cSrcweir 810cdf0e10cSrcweir } 811cdf0e10cSrcweir 812cdf0e10cSrcweir 813cdf0e10cSrcweir 814cdf0e10cSrcweir 815cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::GetWordBoundary( 816cdf0e10cSrcweir const sal_Int32 nLocalCharacterIndex, 817cdf0e10cSrcweir const sal_Int32 nDistance) 818cdf0e10cSrcweir { 819cdf0e10cSrcweir OSL_ASSERT(nDistance==-1 || nDistance==+1); 820cdf0e10cSrcweir 821cdf0e10cSrcweir if (nLocalCharacterIndex < 0) 822cdf0e10cSrcweir { 823cdf0e10cSrcweir // The caller asked for the start or end position of the paragraph. 824cdf0e10cSrcweir if (nDistance < 0) 825cdf0e10cSrcweir return 0; 826cdf0e10cSrcweir else 827cdf0e10cSrcweir return GetCharacterCount(); 828cdf0e10cSrcweir } 829cdf0e10cSrcweir 830cdf0e10cSrcweir sal_Int32 nIndex (0); 831cdf0e10cSrcweir for (sal_Int32 nCount (maWordBoundaries.size()); nIndex<nCount; ++nIndex) 832cdf0e10cSrcweir { 833cdf0e10cSrcweir if (maWordBoundaries[nIndex] >= nLocalCharacterIndex) 834cdf0e10cSrcweir { 835cdf0e10cSrcweir // When inside the word (not at its start or end) then 836cdf0e10cSrcweir // first move to the start or end before going the previous or 837cdf0e10cSrcweir // next word. 838cdf0e10cSrcweir if (maWordBoundaries[nIndex] > nLocalCharacterIndex) 839cdf0e10cSrcweir if (nDistance > 0) 840cdf0e10cSrcweir --nIndex; 841cdf0e10cSrcweir break; 842cdf0e10cSrcweir } 843cdf0e10cSrcweir } 844cdf0e10cSrcweir 845cdf0e10cSrcweir nIndex += nDistance; 846cdf0e10cSrcweir 847cdf0e10cSrcweir if (nIndex < 0) 848cdf0e10cSrcweir return -1; 849cdf0e10cSrcweir else if (sal_uInt32(nIndex)>=maWordBoundaries.size()) 850cdf0e10cSrcweir return -1; 851cdf0e10cSrcweir else 852cdf0e10cSrcweir return maWordBoundaries[nIndex]; 853cdf0e10cSrcweir } 854cdf0e10cSrcweir 855cdf0e10cSrcweir 856cdf0e10cSrcweir 857cdf0e10cSrcweir 858cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::GetCaretPosition (void) const 859cdf0e10cSrcweir { 860cdf0e10cSrcweir if (mpCaret && mpCaret->GetParagraphIndex()==mnParagraphIndex) 861cdf0e10cSrcweir return mpCaret->GetCharacterIndex(); 862cdf0e10cSrcweir else 863cdf0e10cSrcweir return -1; 864cdf0e10cSrcweir } 865cdf0e10cSrcweir 866cdf0e10cSrcweir 867cdf0e10cSrcweir 868cdf0e10cSrcweir 869cdf0e10cSrcweir void PresenterTextParagraph::SetCaretPosition (const sal_Int32 nPosition) const 870cdf0e10cSrcweir { 871cdf0e10cSrcweir if (mpCaret && mpCaret->GetParagraphIndex()==mnParagraphIndex) 872cdf0e10cSrcweir return mpCaret->SetPosition(mnParagraphIndex, nPosition); 873cdf0e10cSrcweir } 874cdf0e10cSrcweir 875cdf0e10cSrcweir 876cdf0e10cSrcweir 877cdf0e10cSrcweir 878cdf0e10cSrcweir void PresenterTextParagraph::SetOrigin (const double nXOrigin, const double nYOrigin) 879cdf0e10cSrcweir { 880cdf0e10cSrcweir mnXOrigin = nXOrigin; 881cdf0e10cSrcweir mnYOrigin = nYOrigin; 882cdf0e10cSrcweir } 883cdf0e10cSrcweir 884cdf0e10cSrcweir 885cdf0e10cSrcweir 886cdf0e10cSrcweir 887cdf0e10cSrcweir awt::Point PresenterTextParagraph::GetRelativeLocation (void) const 888cdf0e10cSrcweir { 889cdf0e10cSrcweir return awt::Point( 890cdf0e10cSrcweir sal_Int32(mnXOrigin), 891cdf0e10cSrcweir sal_Int32(mnYOrigin + mnVerticalOffset)); 892cdf0e10cSrcweir } 893cdf0e10cSrcweir 894cdf0e10cSrcweir 895cdf0e10cSrcweir 896cdf0e10cSrcweir 897cdf0e10cSrcweir awt::Size PresenterTextParagraph::GetSize (void) 898cdf0e10cSrcweir { 899cdf0e10cSrcweir return awt::Size( 900cdf0e10cSrcweir sal_Int32(mnWidth), 901cdf0e10cSrcweir sal_Int32(GetTotalTextHeight())); 902cdf0e10cSrcweir } 903cdf0e10cSrcweir 904cdf0e10cSrcweir 905cdf0e10cSrcweir 906cdf0e10cSrcweir 907cdf0e10cSrcweir void PresenterTextParagraph::AddWord ( 908cdf0e10cSrcweir const double nWidth, 909cdf0e10cSrcweir i18n::Boundary& rCurrentLine, 910cdf0e10cSrcweir const sal_Int32 nWordBoundary, 911cdf0e10cSrcweir const PresenterTheme::SharedFontDescriptor& rpFont) 912cdf0e10cSrcweir { 913cdf0e10cSrcweir sal_Int32 nLineStart (0); 914cdf0e10cSrcweir sal_Int32 nLineEnd (0); 915cdf0e10cSrcweir if ( ! maLines.empty()) 916cdf0e10cSrcweir { 917cdf0e10cSrcweir nLineStart = rCurrentLine.startPos; 918cdf0e10cSrcweir nLineEnd = rCurrentLine.endPos; 919cdf0e10cSrcweir } 920cdf0e10cSrcweir 921cdf0e10cSrcweir const ::rtl::OUString sLineCandidate ( 922cdf0e10cSrcweir msParagraphText.copy(nLineStart, nWordBoundary-nLineStart)); 923cdf0e10cSrcweir 924cdf0e10cSrcweir css::geometry::RealRectangle2D aLineBox ( 925cdf0e10cSrcweir PresenterCanvasHelper::GetTextBoundingBox ( 926cdf0e10cSrcweir rpFont->mxFont, 927cdf0e10cSrcweir sLineCandidate, 928cdf0e10cSrcweir mnWritingMode)); 929cdf0e10cSrcweir const double nLineWidth (aLineBox.X2 - aLineBox.X1); 930cdf0e10cSrcweir 931cdf0e10cSrcweir if (nLineWidth >= nWidth) 932cdf0e10cSrcweir { 933cdf0e10cSrcweir // Add new line with a single word (so far). 934cdf0e10cSrcweir AddLine(rCurrentLine); 935cdf0e10cSrcweir } 936cdf0e10cSrcweir rCurrentLine.endPos = nWordBoundary; 937cdf0e10cSrcweir } 938cdf0e10cSrcweir 939cdf0e10cSrcweir 940cdf0e10cSrcweir 941cdf0e10cSrcweir 942cdf0e10cSrcweir void PresenterTextParagraph::AddLine ( 943cdf0e10cSrcweir i18n::Boundary& rCurrentLine) 944cdf0e10cSrcweir { 945cdf0e10cSrcweir Line aLine (rCurrentLine.startPos, rCurrentLine.endPos); 946cdf0e10cSrcweir 947cdf0e10cSrcweir // Find the start and end of the line with respect to cells. 948cdf0e10cSrcweir if (maLines.size() > 0) 949cdf0e10cSrcweir { 950cdf0e10cSrcweir aLine.mnLineStartCellIndex = maLines.back().mnLineEndCellIndex; 951cdf0e10cSrcweir aLine.mnBaseLine = maLines.back().mnBaseLine + mnLineHeight; 952cdf0e10cSrcweir } 953cdf0e10cSrcweir else 954cdf0e10cSrcweir { 955cdf0e10cSrcweir aLine.mnLineStartCellIndex = 0; 956cdf0e10cSrcweir aLine.mnBaseLine = mnVerticalOffset + mnAscent; 957cdf0e10cSrcweir } 958cdf0e10cSrcweir sal_Int32 nCellIndex (aLine.mnLineStartCellIndex); 959cdf0e10cSrcweir double nWidth (0); 960cdf0e10cSrcweir for ( ; nCellIndex<sal_Int32(maCells.size()); ++nCellIndex) 961cdf0e10cSrcweir { 962cdf0e10cSrcweir const Cell& rCell (maCells[nCellIndex]); 963cdf0e10cSrcweir if (rCell.mnCharacterIndex+rCell.mnCharacterCount > aLine.mnLineEndCharacterIndex) 964cdf0e10cSrcweir break; 965cdf0e10cSrcweir nWidth += rCell.mnCellWidth; 966cdf0e10cSrcweir } 967cdf0e10cSrcweir aLine.mnLineEndCellIndex = nCellIndex; 968cdf0e10cSrcweir aLine.mnWidth = nWidth; 969cdf0e10cSrcweir 970cdf0e10cSrcweir maLines.push_back(aLine); 971cdf0e10cSrcweir 972cdf0e10cSrcweir rCurrentLine.startPos = rCurrentLine.endPos; 973cdf0e10cSrcweir } 974cdf0e10cSrcweir 975cdf0e10cSrcweir 976cdf0e10cSrcweir 977cdf0e10cSrcweir 978cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::GetParagraphIndex (void) const 979cdf0e10cSrcweir { 980cdf0e10cSrcweir return mnParagraphIndex; 981cdf0e10cSrcweir } 982cdf0e10cSrcweir 983cdf0e10cSrcweir 984cdf0e10cSrcweir 985cdf0e10cSrcweir 986cdf0e10cSrcweir double PresenterTextParagraph::GetTotalTextHeight (void) 987cdf0e10cSrcweir { 988cdf0e10cSrcweir return maLines.size() * mnLineHeight; 989cdf0e10cSrcweir } 990cdf0e10cSrcweir 991cdf0e10cSrcweir 992cdf0e10cSrcweir 993cdf0e10cSrcweir 994cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::GetCharacterOffset (void) const 995cdf0e10cSrcweir { 996cdf0e10cSrcweir return mnCharacterOffset; 997cdf0e10cSrcweir } 998cdf0e10cSrcweir 999cdf0e10cSrcweir 1000cdf0e10cSrcweir 1001cdf0e10cSrcweir 1002cdf0e10cSrcweir void PresenterTextParagraph::SetCharacterOffset (const sal_Int32 nCharacterOffset) 1003cdf0e10cSrcweir { 1004cdf0e10cSrcweir mnCharacterOffset = nCharacterOffset; 1005cdf0e10cSrcweir } 1006cdf0e10cSrcweir 1007cdf0e10cSrcweir 1008cdf0e10cSrcweir 1009cdf0e10cSrcweir 1010cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::GetCharacterCount (void) const 1011cdf0e10cSrcweir { 1012cdf0e10cSrcweir return msParagraphText.getLength(); 1013cdf0e10cSrcweir } 1014cdf0e10cSrcweir 1015cdf0e10cSrcweir 1016cdf0e10cSrcweir 1017cdf0e10cSrcweir 1018cdf0e10cSrcweir sal_Unicode PresenterTextParagraph::GetCharacter ( 1019cdf0e10cSrcweir const sal_Int32 nGlobalCharacterIndex) const 1020cdf0e10cSrcweir { 1021cdf0e10cSrcweir if (nGlobalCharacterIndex<mnCharacterOffset 1022cdf0e10cSrcweir || nGlobalCharacterIndex>=mnCharacterOffset+msParagraphText.getLength()) 1023cdf0e10cSrcweir { 1024cdf0e10cSrcweir return sal_Unicode(); 1025cdf0e10cSrcweir } 1026cdf0e10cSrcweir else 1027cdf0e10cSrcweir { 1028cdf0e10cSrcweir return msParagraphText.getStr()[nGlobalCharacterIndex - mnCharacterOffset]; 1029cdf0e10cSrcweir } 1030cdf0e10cSrcweir } 1031cdf0e10cSrcweir 1032cdf0e10cSrcweir 1033cdf0e10cSrcweir 1034cdf0e10cSrcweir 1035cdf0e10cSrcweir ::rtl::OUString PresenterTextParagraph::GetText (void) const 1036cdf0e10cSrcweir { 1037cdf0e10cSrcweir return msParagraphText; 1038cdf0e10cSrcweir } 1039cdf0e10cSrcweir 1040cdf0e10cSrcweir 1041cdf0e10cSrcweir 1042cdf0e10cSrcweir 1043cdf0e10cSrcweir TextSegment PresenterTextParagraph::GetTextSegment ( 1044cdf0e10cSrcweir const sal_Int32 nOffset, 1045cdf0e10cSrcweir const sal_Int32 nIndex, 1046cdf0e10cSrcweir const sal_Int16 nTextType) const 1047cdf0e10cSrcweir { 1048cdf0e10cSrcweir switch(nTextType) 1049cdf0e10cSrcweir { 1050cdf0e10cSrcweir case AccessibleTextType::PARAGRAPH: 1051cdf0e10cSrcweir return TextSegment( 1052cdf0e10cSrcweir msParagraphText, 1053cdf0e10cSrcweir mnCharacterOffset, 1054cdf0e10cSrcweir mnCharacterOffset+msParagraphText.getLength()); 1055cdf0e10cSrcweir 1056cdf0e10cSrcweir case AccessibleTextType::SENTENCE: 1057cdf0e10cSrcweir if (mxBreakIterator.is()) 1058cdf0e10cSrcweir { 1059cdf0e10cSrcweir const sal_Int32 nStart (mxBreakIterator->beginOfSentence( 1060cdf0e10cSrcweir msParagraphText, nIndex-mnCharacterOffset, lang::Locale())); 1061cdf0e10cSrcweir const sal_Int32 nEnd (mxBreakIterator->endOfSentence( 1062cdf0e10cSrcweir msParagraphText, nIndex-mnCharacterOffset, lang::Locale())); 1063cdf0e10cSrcweir if (nStart < nEnd) 1064cdf0e10cSrcweir return TextSegment( 1065cdf0e10cSrcweir msParagraphText.copy(nStart, nEnd-nStart), 1066cdf0e10cSrcweir nStart+mnCharacterOffset, 1067cdf0e10cSrcweir nEnd+mnCharacterOffset); 1068cdf0e10cSrcweir } 1069cdf0e10cSrcweir break; 1070cdf0e10cSrcweir 1071cdf0e10cSrcweir case AccessibleTextType::WORD: 1072cdf0e10cSrcweir if (mxBreakIterator.is()) 1073cdf0e10cSrcweir return GetWordTextSegment(nOffset, nIndex); 1074cdf0e10cSrcweir break; 1075cdf0e10cSrcweir 1076cdf0e10cSrcweir case AccessibleTextType::LINE: 1077cdf0e10cSrcweir { 1078cdf0e10cSrcweir for (::std::vector<Line>::const_iterator 1079cdf0e10cSrcweir iLine(maLines.begin()), 1080cdf0e10cSrcweir iEnd(maLines.end()); 1081cdf0e10cSrcweir iLine!=iEnd; 1082cdf0e10cSrcweir ++iLine) 1083cdf0e10cSrcweir { 1084cdf0e10cSrcweir if (nIndex < iLine->mnLineEndCharacterIndex) 1085cdf0e10cSrcweir { 1086cdf0e10cSrcweir return TextSegment( 1087cdf0e10cSrcweir msParagraphText.copy( 1088cdf0e10cSrcweir iLine->mnLineStartCharacterIndex, 1089cdf0e10cSrcweir iLine->mnLineEndCharacterIndex - iLine->mnLineStartCharacterIndex), 1090cdf0e10cSrcweir iLine->mnLineStartCharacterIndex, 1091cdf0e10cSrcweir iLine->mnLineEndCharacterIndex); 1092cdf0e10cSrcweir } 1093cdf0e10cSrcweir } 1094cdf0e10cSrcweir } 1095cdf0e10cSrcweir break; 1096cdf0e10cSrcweir 1097cdf0e10cSrcweir // Handle GLYPH and ATTRIBUTE_RUN like CHARACTER because we can not 1098cdf0e10cSrcweir // do better at the moment. 1099cdf0e10cSrcweir case AccessibleTextType::CHARACTER: 1100cdf0e10cSrcweir case AccessibleTextType::GLYPH: 1101cdf0e10cSrcweir case AccessibleTextType::ATTRIBUTE_RUN: 1102cdf0e10cSrcweir return CreateTextSegment(nIndex+nOffset, nIndex+nOffset+1); 1103cdf0e10cSrcweir } 1104cdf0e10cSrcweir 1105cdf0e10cSrcweir return TextSegment(::rtl::OUString(), 0,0); 1106cdf0e10cSrcweir } 1107cdf0e10cSrcweir 1108cdf0e10cSrcweir 1109cdf0e10cSrcweir 1110cdf0e10cSrcweir 1111cdf0e10cSrcweir TextSegment PresenterTextParagraph::GetWordTextSegment ( 1112cdf0e10cSrcweir const sal_Int32 nOffset, 1113cdf0e10cSrcweir const sal_Int32 nIndex) const 1114cdf0e10cSrcweir { 1115cdf0e10cSrcweir sal_Int32 nCurrentOffset (nOffset); 1116cdf0e10cSrcweir sal_Int32 nCurrentIndex (nIndex); 1117cdf0e10cSrcweir 1118cdf0e10cSrcweir i18n::Boundary aWordBoundary; 1119cdf0e10cSrcweir if (nCurrentOffset == 0) 1120cdf0e10cSrcweir aWordBoundary = mxBreakIterator->getWordBoundary( 1121cdf0e10cSrcweir msParagraphText, 1122cdf0e10cSrcweir nIndex, 1123cdf0e10cSrcweir lang::Locale(), 1124cdf0e10cSrcweir i18n::WordType::ANYWORD_IGNOREWHITESPACES, 1125cdf0e10cSrcweir sal_True); 1126cdf0e10cSrcweir else if (nCurrentOffset < 0) 1127cdf0e10cSrcweir { 1128cdf0e10cSrcweir while (nCurrentOffset<0 && nCurrentIndex>0) 1129cdf0e10cSrcweir { 1130cdf0e10cSrcweir aWordBoundary = mxBreakIterator->previousWord( 1131cdf0e10cSrcweir msParagraphText, 1132cdf0e10cSrcweir nCurrentIndex, 1133cdf0e10cSrcweir lang::Locale(), 1134cdf0e10cSrcweir i18n::WordType::ANYWORD_IGNOREWHITESPACES); 1135cdf0e10cSrcweir nCurrentIndex = aWordBoundary.startPos; 1136cdf0e10cSrcweir ++nCurrentOffset; 1137cdf0e10cSrcweir } 1138cdf0e10cSrcweir } 1139cdf0e10cSrcweir else 1140cdf0e10cSrcweir { 1141cdf0e10cSrcweir while (nCurrentOffset>0 && nCurrentIndex<=GetCharacterCount()) 1142cdf0e10cSrcweir { 1143cdf0e10cSrcweir aWordBoundary = mxBreakIterator->nextWord( 1144cdf0e10cSrcweir msParagraphText, 1145cdf0e10cSrcweir nCurrentIndex, 1146cdf0e10cSrcweir lang::Locale(), 1147cdf0e10cSrcweir i18n::WordType::ANYWORD_IGNOREWHITESPACES); 1148cdf0e10cSrcweir nCurrentIndex = aWordBoundary.endPos; 1149cdf0e10cSrcweir --nCurrentOffset; 1150cdf0e10cSrcweir } 1151cdf0e10cSrcweir } 1152cdf0e10cSrcweir 1153cdf0e10cSrcweir return CreateTextSegment(aWordBoundary.startPos, aWordBoundary.endPos); 1154cdf0e10cSrcweir } 1155cdf0e10cSrcweir 1156cdf0e10cSrcweir 1157cdf0e10cSrcweir 1158cdf0e10cSrcweir 1159cdf0e10cSrcweir TextSegment PresenterTextParagraph::CreateTextSegment ( 1160cdf0e10cSrcweir sal_Int32 nStartIndex, 1161cdf0e10cSrcweir sal_Int32 nEndIndex) const 1162cdf0e10cSrcweir { 1163cdf0e10cSrcweir if (nEndIndex <= nStartIndex) 1164cdf0e10cSrcweir return TextSegment( 1165cdf0e10cSrcweir ::rtl::OUString(), 1166cdf0e10cSrcweir nStartIndex, 1167cdf0e10cSrcweir nEndIndex); 1168cdf0e10cSrcweir else 1169cdf0e10cSrcweir return TextSegment( 1170cdf0e10cSrcweir msParagraphText.copy(nStartIndex, nEndIndex-nStartIndex), 1171cdf0e10cSrcweir nStartIndex, 1172cdf0e10cSrcweir nEndIndex); 1173cdf0e10cSrcweir } 1174cdf0e10cSrcweir 1175cdf0e10cSrcweir 1176cdf0e10cSrcweir 1177cdf0e10cSrcweir 1178cdf0e10cSrcweir awt::Rectangle PresenterTextParagraph::GetCharacterBounds ( 1179cdf0e10cSrcweir sal_Int32 nGlobalCharacterIndex, 1180cdf0e10cSrcweir const bool bCaretBox) 1181cdf0e10cSrcweir { 1182cdf0e10cSrcweir // Find the line that contains the requested character and accumulate 1183cdf0e10cSrcweir // the previous line heights. 1184cdf0e10cSrcweir sal_Int32 nFirstCharacterIndex (0); 1185cdf0e10cSrcweir sal_Int32 nEndCharacterIndex (0); 1186cdf0e10cSrcweir double nX (mnXOrigin); 1187cdf0e10cSrcweir double nY (mnYOrigin + mnVerticalOffset + mnAscent); 1188cdf0e10cSrcweir const sal_Int8 nTextDirection (GetTextDirection()); 1189cdf0e10cSrcweir for (sal_Int32 nLineIndex=0,nLineCount=maLines.size(); 1190cdf0e10cSrcweir nLineIndex<nLineCount; 1191cdf0e10cSrcweir ++nLineIndex, nFirstCharacterIndex=nEndCharacterIndex, nY+=mnLineHeight) 1192cdf0e10cSrcweir { 1193cdf0e10cSrcweir Line& rLine (maLines[nLineIndex]); 1194cdf0e10cSrcweir // Skip lines before the indexed character. 1195cdf0e10cSrcweir if (nGlobalCharacterIndex >= rLine.mnLineEndCharacterIndex) 1196cdf0e10cSrcweir // When in the last line then allow the index past the last char. 1197cdf0e10cSrcweir if (nLineIndex<nLineCount-1) 1198cdf0e10cSrcweir continue; 1199cdf0e10cSrcweir 1200cdf0e10cSrcweir rLine.ProvideCellBoxes(); 1201cdf0e10cSrcweir 1202cdf0e10cSrcweir const sal_Int32 nCellIndex (nGlobalCharacterIndex - rLine.mnLineStartCharacterIndex); 1203cdf0e10cSrcweir 1204cdf0e10cSrcweir // The cell bounding box is defined relative to the origin of 1205cdf0e10cSrcweir // the current line. Therefore we have to add the absolute 1206cdf0e10cSrcweir // position of the line. 1207cdf0e10cSrcweir geometry::RealRectangle2D rCellBox (rLine.maCellBoxes[ 1208cdf0e10cSrcweir ::std::min(nCellIndex, rLine.maCellBoxes.getLength()-1)]); 1209cdf0e10cSrcweir 1210cdf0e10cSrcweir double nLeft = nX + rCellBox.X1; 1211cdf0e10cSrcweir double nRight = nX + rCellBox.X2; 1212cdf0e10cSrcweir if (nTextDirection == rendering::TextDirection::WEAK_RIGHT_TO_LEFT) 1213cdf0e10cSrcweir { 1214cdf0e10cSrcweir const double nOldRight (nRight); 1215cdf0e10cSrcweir nRight = rLine.mnWidth - nLeft; 1216cdf0e10cSrcweir nLeft = rLine.mnWidth - nOldRight; 1217cdf0e10cSrcweir } 1218cdf0e10cSrcweir double nTop (nY + rCellBox.Y1); 1219cdf0e10cSrcweir double nBottom (nY + rCellBox.Y2); 1220cdf0e10cSrcweir if (bCaretBox) 1221cdf0e10cSrcweir { 1222cdf0e10cSrcweir nTop = nTop - rCellBox.Y1 - mnAscent; 1223cdf0e10cSrcweir nBottom = nTop + mnLineHeight; 1224cdf0e10cSrcweir if (nCellIndex >= rLine.maCellBoxes.getLength()) 1225cdf0e10cSrcweir nLeft = nRight-2; 1226cdf0e10cSrcweir if (nLeft < nX) 1227cdf0e10cSrcweir nLeft = nX; 1228cdf0e10cSrcweir nRight = nLeft+2; 1229cdf0e10cSrcweir } 1230cdf0e10cSrcweir else 1231cdf0e10cSrcweir { 1232cdf0e10cSrcweir nTop = nTop - rCellBox.Y1 - mnAscent; 1233cdf0e10cSrcweir nBottom = nTop + mnAscent + mnDescent; 1234cdf0e10cSrcweir } 1235cdf0e10cSrcweir const sal_Int32 nX1 = sal_Int32(floor(nLeft)); 1236cdf0e10cSrcweir const sal_Int32 nY1 = sal_Int32(floor(nTop)); 1237cdf0e10cSrcweir const sal_Int32 nX2 = sal_Int32(ceil(nRight)); 1238cdf0e10cSrcweir const sal_Int32 nY2 = sal_Int32(ceil(nBottom)); 1239cdf0e10cSrcweir 1240cdf0e10cSrcweir return awt::Rectangle(nX1,nY1,nX2-nX1+1,nY2-nY1+1); 1241cdf0e10cSrcweir } 1242cdf0e10cSrcweir 1243cdf0e10cSrcweir // We are still here. That means that the given index lies past the 1244cdf0e10cSrcweir // last character in the paragraph. 1245cdf0e10cSrcweir // Return an empty box that lies past the last character. Better than nothing. 1246cdf0e10cSrcweir return awt::Rectangle(sal_Int32(nX+0.5), sal_Int32(nY+0.5), 0, 0); 1247cdf0e10cSrcweir } 1248cdf0e10cSrcweir 1249cdf0e10cSrcweir 1250cdf0e10cSrcweir 1251cdf0e10cSrcweir 1252cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::GetIndexAtPoint (const awt::Point& rPoint) const 1253cdf0e10cSrcweir { 1254cdf0e10cSrcweir (void)rPoint; 1255cdf0e10cSrcweir return -1; 1256cdf0e10cSrcweir } 1257cdf0e10cSrcweir 1258cdf0e10cSrcweir 1259cdf0e10cSrcweir 1260cdf0e10cSrcweir 1261cdf0e10cSrcweir sal_Int8 PresenterTextParagraph::GetTextDirection (void) const 1262cdf0e10cSrcweir { 1263cdf0e10cSrcweir // Find first portion that has a non-neutral text direction. 1264cdf0e10cSrcweir sal_Int32 nPosition (0); 1265cdf0e10cSrcweir sal_Int32 nTextLength (msParagraphText.getLength()); 1266cdf0e10cSrcweir while (nPosition < nTextLength) 1267cdf0e10cSrcweir { 1268cdf0e10cSrcweir const sal_Int16 nScriptDirection ( 1269cdf0e10cSrcweir mxScriptTypeDetector->getScriptDirection( 1270cdf0e10cSrcweir msParagraphText, nPosition, i18n::ScriptDirection::NEUTRAL)); 1271cdf0e10cSrcweir switch (nScriptDirection) 1272cdf0e10cSrcweir { 1273cdf0e10cSrcweir case i18n::ScriptDirection::NEUTRAL: 1274cdf0e10cSrcweir // continue looping. 1275cdf0e10cSrcweir break; 1276cdf0e10cSrcweir case i18n::ScriptDirection::LEFT_TO_RIGHT: 1277cdf0e10cSrcweir return rendering::TextDirection::WEAK_LEFT_TO_RIGHT; 1278cdf0e10cSrcweir 1279cdf0e10cSrcweir case i18n::ScriptDirection::RIGHT_TO_LEFT: 1280cdf0e10cSrcweir return rendering::TextDirection::WEAK_RIGHT_TO_LEFT; 1281cdf0e10cSrcweir } 1282cdf0e10cSrcweir 1283cdf0e10cSrcweir nPosition = mxScriptTypeDetector->endOfScriptDirection( 1284cdf0e10cSrcweir msParagraphText, nPosition, nScriptDirection); 1285cdf0e10cSrcweir } 1286cdf0e10cSrcweir 1287cdf0e10cSrcweir // All text in paragraph is neutral. Fall back on writing mode taken 1288cdf0e10cSrcweir // from the XText (which may not be properly initialized.) 1289cdf0e10cSrcweir sal_Int8 nTextDirection(rendering::TextDirection::WEAK_LEFT_TO_RIGHT); 1290cdf0e10cSrcweir switch(mnWritingMode) 1291cdf0e10cSrcweir { 1292cdf0e10cSrcweir case text::WritingMode2::LR_TB: 1293cdf0e10cSrcweir nTextDirection = rendering::TextDirection::WEAK_LEFT_TO_RIGHT; 1294cdf0e10cSrcweir break; 1295cdf0e10cSrcweir 1296cdf0e10cSrcweir case text::WritingMode2::RL_TB: 1297cdf0e10cSrcweir nTextDirection = rendering::TextDirection::WEAK_RIGHT_TO_LEFT; 1298cdf0e10cSrcweir break; 1299cdf0e10cSrcweir 1300cdf0e10cSrcweir default: 1301cdf0e10cSrcweir case text::WritingMode2::TB_RL: 1302cdf0e10cSrcweir case text::WritingMode2::TB_LR: 1303cdf0e10cSrcweir // Can not handle this. Use default and hope for the best. 1304cdf0e10cSrcweir break; 1305cdf0e10cSrcweir } 1306cdf0e10cSrcweir return nTextDirection; 1307cdf0e10cSrcweir } 1308cdf0e10cSrcweir 1309cdf0e10cSrcweir 1310cdf0e10cSrcweir 1311cdf0e10cSrcweir 1312cdf0e10cSrcweir bool PresenterTextParagraph::IsTextReferencePointLeft (void) const 1313cdf0e10cSrcweir { 1314cdf0e10cSrcweir return mnWritingMode != text::WritingMode2::RL_TB; 1315cdf0e10cSrcweir } 1316cdf0e10cSrcweir 1317cdf0e10cSrcweir 1318cdf0e10cSrcweir 1319cdf0e10cSrcweir 1320cdf0e10cSrcweir void PresenterTextParagraph::SetupCellArray ( 1321cdf0e10cSrcweir const PresenterTheme::SharedFontDescriptor& rpFont) 1322cdf0e10cSrcweir { 1323cdf0e10cSrcweir maCells.clear(); 1324cdf0e10cSrcweir 1325cdf0e10cSrcweir if ( ! rpFont || ! rpFont->mxFont.is()) 1326cdf0e10cSrcweir return; 1327cdf0e10cSrcweir 1328cdf0e10cSrcweir sal_Int32 nPosition (0); 1329cdf0e10cSrcweir sal_Int32 nIndex (0); 1330cdf0e10cSrcweir const sal_Int32 nTextLength (msParagraphText.getLength()); 1331cdf0e10cSrcweir const sal_Int8 nTextDirection (GetTextDirection()); 1332cdf0e10cSrcweir while (nPosition < nTextLength) 1333cdf0e10cSrcweir { 1334cdf0e10cSrcweir const sal_Int32 nNewPosition (mxBreakIterator->nextCharacters( 1335cdf0e10cSrcweir msParagraphText, 1336cdf0e10cSrcweir nPosition, 1337cdf0e10cSrcweir lang::Locale(), 1338cdf0e10cSrcweir i18n::CharacterIteratorMode::SKIPCELL, 1339cdf0e10cSrcweir 1, 1340cdf0e10cSrcweir nIndex)); 1341cdf0e10cSrcweir 1342cdf0e10cSrcweir rendering::StringContext aContext (msParagraphText, nPosition, nNewPosition-nPosition); 1343cdf0e10cSrcweir Reference<rendering::XTextLayout> xLayout ( 1344cdf0e10cSrcweir rpFont->mxFont->createTextLayout(aContext, nTextDirection, 0)); 1345cdf0e10cSrcweir css::geometry::RealRectangle2D aCharacterBox (xLayout->queryTextBounds()); 1346cdf0e10cSrcweir 1347cdf0e10cSrcweir maCells.push_back(Cell( 1348cdf0e10cSrcweir nPosition, 1349cdf0e10cSrcweir nNewPosition-nPosition, 1350cdf0e10cSrcweir aCharacterBox.X2-aCharacterBox.X1)); 1351cdf0e10cSrcweir 1352cdf0e10cSrcweir nPosition = nNewPosition; 1353cdf0e10cSrcweir } 1354cdf0e10cSrcweir } 1355cdf0e10cSrcweir 1356cdf0e10cSrcweir 1357cdf0e10cSrcweir 1358cdf0e10cSrcweir 1359cdf0e10cSrcweir //===== PresenterTextCaret ================================================---- 1360cdf0e10cSrcweir 1361cdf0e10cSrcweir PresenterTextCaret::PresenterTextCaret ( 1362cdf0e10cSrcweir const ::boost::function<css::awt::Rectangle(const sal_Int32,const sal_Int32)>& rCharacterBoundsAccess, 1363cdf0e10cSrcweir const ::boost::function<void(const css::awt::Rectangle&)>& rInvalidator) 1364cdf0e10cSrcweir : mnParagraphIndex(-1), 1365cdf0e10cSrcweir mnCharacterIndex(-1), 1366cdf0e10cSrcweir mnCaretBlinkTaskId(0), 1367cdf0e10cSrcweir mbIsCaretVisible(false), 1368cdf0e10cSrcweir maCharacterBoundsAccess(rCharacterBoundsAccess), 1369cdf0e10cSrcweir maInvalidator(rInvalidator), 1370cdf0e10cSrcweir maBroadcaster(), 1371cdf0e10cSrcweir maCaretBounds() 1372cdf0e10cSrcweir { 1373cdf0e10cSrcweir } 1374cdf0e10cSrcweir 1375cdf0e10cSrcweir 1376cdf0e10cSrcweir 1377cdf0e10cSrcweir 1378cdf0e10cSrcweir PresenterTextCaret::~PresenterTextCaret (void) 1379cdf0e10cSrcweir { 1380cdf0e10cSrcweir HideCaret(); 1381cdf0e10cSrcweir } 1382cdf0e10cSrcweir 1383cdf0e10cSrcweir 1384cdf0e10cSrcweir 1385cdf0e10cSrcweir 1386cdf0e10cSrcweir void PresenterTextCaret::ShowCaret (void) 1387cdf0e10cSrcweir { 1388cdf0e10cSrcweir if (mnCaretBlinkTaskId == 0) 1389cdf0e10cSrcweir { 1390cdf0e10cSrcweir mnCaretBlinkTaskId = PresenterTimer::ScheduleRepeatedTask ( 1391cdf0e10cSrcweir ::boost::bind(&PresenterTextCaret::InvertCaret, this), 1392cdf0e10cSrcweir CaretBlinkIntervall, 1393cdf0e10cSrcweir CaretBlinkIntervall); 1394cdf0e10cSrcweir } 1395cdf0e10cSrcweir mbIsCaretVisible = true; 1396cdf0e10cSrcweir } 1397cdf0e10cSrcweir 1398cdf0e10cSrcweir 1399cdf0e10cSrcweir 1400cdf0e10cSrcweir 1401cdf0e10cSrcweir void PresenterTextCaret::HideCaret (void) 1402cdf0e10cSrcweir { 1403cdf0e10cSrcweir if (mnCaretBlinkTaskId != 0) 1404cdf0e10cSrcweir { 1405cdf0e10cSrcweir PresenterTimer::CancelTask(mnCaretBlinkTaskId); 1406cdf0e10cSrcweir mnCaretBlinkTaskId = 0; 1407cdf0e10cSrcweir } 1408cdf0e10cSrcweir mbIsCaretVisible = false; 1409cdf0e10cSrcweir // Reset the caret position. 1410cdf0e10cSrcweir mnParagraphIndex = -1; 1411cdf0e10cSrcweir mnCharacterIndex = -1; 1412cdf0e10cSrcweir } 1413cdf0e10cSrcweir 1414cdf0e10cSrcweir 1415cdf0e10cSrcweir 1416cdf0e10cSrcweir 1417cdf0e10cSrcweir sal_Int32 PresenterTextCaret::GetParagraphIndex (void) const 1418cdf0e10cSrcweir { 1419cdf0e10cSrcweir return mnParagraphIndex; 1420cdf0e10cSrcweir } 1421cdf0e10cSrcweir 1422cdf0e10cSrcweir 1423cdf0e10cSrcweir 1424cdf0e10cSrcweir 1425cdf0e10cSrcweir sal_Int32 PresenterTextCaret::GetCharacterIndex (void) const 1426cdf0e10cSrcweir { 1427cdf0e10cSrcweir return mnCharacterIndex; 1428cdf0e10cSrcweir } 1429cdf0e10cSrcweir 1430cdf0e10cSrcweir 1431cdf0e10cSrcweir 1432cdf0e10cSrcweir 1433cdf0e10cSrcweir void PresenterTextCaret::SetPosition ( 1434cdf0e10cSrcweir const sal_Int32 nParagraphIndex, 1435cdf0e10cSrcweir const sal_Int32 nCharacterIndex) 1436cdf0e10cSrcweir { 1437cdf0e10cSrcweir if (mnParagraphIndex != nParagraphIndex 1438cdf0e10cSrcweir || mnCharacterIndex != nCharacterIndex) 1439cdf0e10cSrcweir { 1440cdf0e10cSrcweir if (mnParagraphIndex >= 0) 1441cdf0e10cSrcweir maInvalidator(maCaretBounds); 1442cdf0e10cSrcweir 1443cdf0e10cSrcweir const sal_Int32 nOldParagraphIndex (mnParagraphIndex); 1444cdf0e10cSrcweir const sal_Int32 nOldCharacterIndex (mnCharacterIndex); 1445cdf0e10cSrcweir mnParagraphIndex = nParagraphIndex; 1446cdf0e10cSrcweir mnCharacterIndex = nCharacterIndex; 1447cdf0e10cSrcweir maCaretBounds = maCharacterBoundsAccess(mnParagraphIndex, mnCharacterIndex); 1448cdf0e10cSrcweir if (mnParagraphIndex >= 0) 1449cdf0e10cSrcweir ShowCaret(); 1450cdf0e10cSrcweir else 1451cdf0e10cSrcweir HideCaret(); 1452cdf0e10cSrcweir 1453cdf0e10cSrcweir if (mnParagraphIndex >= 0) 1454cdf0e10cSrcweir maInvalidator(maCaretBounds); 1455cdf0e10cSrcweir 1456cdf0e10cSrcweir if (maBroadcaster) 1457cdf0e10cSrcweir maBroadcaster( 1458cdf0e10cSrcweir nOldParagraphIndex, 1459cdf0e10cSrcweir nOldCharacterIndex, 1460cdf0e10cSrcweir mnParagraphIndex, 1461cdf0e10cSrcweir mnCharacterIndex); 1462cdf0e10cSrcweir 1463cdf0e10cSrcweir } 1464cdf0e10cSrcweir } 1465cdf0e10cSrcweir 1466cdf0e10cSrcweir 1467cdf0e10cSrcweir 1468cdf0e10cSrcweir 1469cdf0e10cSrcweir bool PresenterTextCaret::IsVisible (void) const 1470cdf0e10cSrcweir { 1471cdf0e10cSrcweir return mbIsCaretVisible; 1472cdf0e10cSrcweir } 1473cdf0e10cSrcweir 1474cdf0e10cSrcweir 1475cdf0e10cSrcweir 1476cdf0e10cSrcweir 1477cdf0e10cSrcweir void PresenterTextCaret::SetCaretMotionBroadcaster ( 1478cdf0e10cSrcweir const ::boost::function<void(sal_Int32,sal_Int32,sal_Int32,sal_Int32)>& rBroadcaster) 1479cdf0e10cSrcweir { 1480cdf0e10cSrcweir maBroadcaster = rBroadcaster; 1481cdf0e10cSrcweir } 1482cdf0e10cSrcweir 1483cdf0e10cSrcweir 1484cdf0e10cSrcweir 1485cdf0e10cSrcweir 1486cdf0e10cSrcweir css::awt::Rectangle PresenterTextCaret::GetBounds (void) const 1487cdf0e10cSrcweir { 1488cdf0e10cSrcweir return maCaretBounds; 1489cdf0e10cSrcweir } 1490cdf0e10cSrcweir 1491cdf0e10cSrcweir 1492cdf0e10cSrcweir 1493cdf0e10cSrcweir 1494cdf0e10cSrcweir void PresenterTextCaret::InvertCaret (void) 1495cdf0e10cSrcweir { 1496cdf0e10cSrcweir mbIsCaretVisible = !mbIsCaretVisible; 1497cdf0e10cSrcweir if (mnParagraphIndex >= 0) 1498cdf0e10cSrcweir maInvalidator(maCaretBounds); 1499cdf0e10cSrcweir } 1500cdf0e10cSrcweir 1501cdf0e10cSrcweir 1502cdf0e10cSrcweir 1503cdf0e10cSrcweir 1504cdf0e10cSrcweir 1505cdf0e10cSrcweir 1506cdf0e10cSrcweir 1507cdf0e10cSrcweir //===== PresenterTextParagraph::Cell ========================================== 1508cdf0e10cSrcweir 1509cdf0e10cSrcweir PresenterTextParagraph::Cell::Cell ( 1510cdf0e10cSrcweir const sal_Int32 nCharacterIndex, 1511cdf0e10cSrcweir const sal_Int32 nCharacterCount, 1512cdf0e10cSrcweir const double nCellWidth) 1513cdf0e10cSrcweir : mnCharacterIndex(nCharacterIndex), 1514cdf0e10cSrcweir mnCharacterCount(nCharacterCount), 1515cdf0e10cSrcweir mnCellWidth(nCellWidth) 1516cdf0e10cSrcweir { 1517cdf0e10cSrcweir } 1518cdf0e10cSrcweir 1519cdf0e10cSrcweir 1520cdf0e10cSrcweir 1521cdf0e10cSrcweir 1522cdf0e10cSrcweir //===== PresenterTextParagraph::Line ========================================== 1523cdf0e10cSrcweir 1524cdf0e10cSrcweir PresenterTextParagraph::Line::Line ( 1525cdf0e10cSrcweir const sal_Int32 nLineStartCharacterIndex, 1526cdf0e10cSrcweir const sal_Int32 nLineEndCharacterIndex) 1527cdf0e10cSrcweir : mnLineStartCharacterIndex(nLineStartCharacterIndex), 1528cdf0e10cSrcweir mnLineEndCharacterIndex(nLineEndCharacterIndex), 1529cdf0e10cSrcweir mnLineStartCellIndex(-1), mnLineEndCellIndex(-1), 1530cdf0e10cSrcweir mxLayoutedLine(), 1531cdf0e10cSrcweir mnBaseLine(0), mnWidth(0), 1532cdf0e10cSrcweir maCellBoxes() 1533cdf0e10cSrcweir { 1534cdf0e10cSrcweir } 1535cdf0e10cSrcweir 1536cdf0e10cSrcweir 1537cdf0e10cSrcweir 1538cdf0e10cSrcweir 1539cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::Line::GetLength (void) const 1540cdf0e10cSrcweir { 1541cdf0e10cSrcweir return mnLineEndCharacterIndex-mnLineStartCharacterIndex; 1542cdf0e10cSrcweir } 1543cdf0e10cSrcweir 1544cdf0e10cSrcweir 1545cdf0e10cSrcweir 1546cdf0e10cSrcweir 1547cdf0e10cSrcweir void PresenterTextParagraph::Line::ProvideCellBoxes (void) 1548cdf0e10cSrcweir { 1549cdf0e10cSrcweir if ( ! IsEmpty() && maCellBoxes.getLength()==0) 1550cdf0e10cSrcweir { 1551cdf0e10cSrcweir if (mxLayoutedLine.is()) 1552cdf0e10cSrcweir maCellBoxes = mxLayoutedLine->queryInkMeasures(); 1553cdf0e10cSrcweir else 1554cdf0e10cSrcweir { 1555cdf0e10cSrcweir OSL_ASSERT(mxLayoutedLine.is()); 1556cdf0e10cSrcweir } 1557cdf0e10cSrcweir } 1558cdf0e10cSrcweir } 1559cdf0e10cSrcweir 1560cdf0e10cSrcweir 1561cdf0e10cSrcweir 1562cdf0e10cSrcweir 1563cdf0e10cSrcweir void PresenterTextParagraph::Line::ProvideLayoutedLine ( 1564cdf0e10cSrcweir const ::rtl::OUString& rsParagraphText, 1565cdf0e10cSrcweir const PresenterTheme::SharedFontDescriptor& rpFont, 1566cdf0e10cSrcweir const sal_Int8 nTextDirection) 1567cdf0e10cSrcweir { 1568cdf0e10cSrcweir if ( ! mxLayoutedLine.is()) 1569cdf0e10cSrcweir { 1570cdf0e10cSrcweir const rendering::StringContext aContext ( 1571cdf0e10cSrcweir rsParagraphText, 1572cdf0e10cSrcweir mnLineStartCharacterIndex, 1573cdf0e10cSrcweir mnLineEndCharacterIndex - mnLineStartCharacterIndex); 1574cdf0e10cSrcweir 1575cdf0e10cSrcweir mxLayoutedLine = rpFont->mxFont->createTextLayout( 1576cdf0e10cSrcweir aContext, 1577cdf0e10cSrcweir nTextDirection, 1578cdf0e10cSrcweir 0); 1579cdf0e10cSrcweir } 1580cdf0e10cSrcweir } 1581cdf0e10cSrcweir 1582cdf0e10cSrcweir 1583cdf0e10cSrcweir 1584cdf0e10cSrcweir 1585cdf0e10cSrcweir bool PresenterTextParagraph::Line::IsEmpty (void) const 1586cdf0e10cSrcweir { 1587cdf0e10cSrcweir return mnLineStartCharacterIndex >= mnLineEndCharacterIndex; 1588cdf0e10cSrcweir } 1589cdf0e10cSrcweir 1590cdf0e10cSrcweir 1591cdf0e10cSrcweir 1592cdf0e10cSrcweir 1593cdf0e10cSrcweir } } // end of namespace ::sdext::presenter 1594