1*2822fc04SHerbert Dürr /************************************************************** 2*2822fc04SHerbert Dürr * 3*2822fc04SHerbert Dürr * Licensed to the Apache Software Foundation (ASF) under one 4*2822fc04SHerbert Dürr * or more contributor license agreements. See the NOTICE file 5*2822fc04SHerbert Dürr * distributed with this work for additional information 6*2822fc04SHerbert Dürr * regarding copyright ownership. The ASF licenses this file 7*2822fc04SHerbert Dürr * to you under the Apache License, Version 2.0 (the 8*2822fc04SHerbert Dürr * "License"); you may not use this file except in compliance 9*2822fc04SHerbert Dürr * with the License. You may obtain a copy of the License at 10*2822fc04SHerbert Dürr * 11*2822fc04SHerbert Dürr * http://www.apache.org/licenses/LICENSE-2.0 12*2822fc04SHerbert Dürr * 13*2822fc04SHerbert Dürr * Unless required by applicable law or agreed to in writing, 14*2822fc04SHerbert Dürr * software distributed under the License is distributed on an 15*2822fc04SHerbert Dürr * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*2822fc04SHerbert Dürr * KIND, either express or implied. See the License for the 17*2822fc04SHerbert Dürr * specific language governing permissions and limitations 18*2822fc04SHerbert Dürr * under the License. 19*2822fc04SHerbert Dürr * 20*2822fc04SHerbert Dürr *************************************************************/ 21*2822fc04SHerbert Dürr 22*2822fc04SHerbert Dürr //#include "salgdi.hxx" 23*2822fc04SHerbert Dürr #include "tools/debug.hxx" 24*2822fc04SHerbert Dürr 25*2822fc04SHerbert Dürr #include "ctfonts.hxx" 26*2822fc04SHerbert Dürr 27*2822fc04SHerbert Dürr // ======================================================================= 28*2822fc04SHerbert Dürr 29*2822fc04SHerbert Dürr class CTLayout 30*2822fc04SHerbert Dürr : public SalLayout 31*2822fc04SHerbert Dürr { 32*2822fc04SHerbert Dürr public: 33*2822fc04SHerbert Dürr explicit CTLayout( const CTTextStyle* ); 34*2822fc04SHerbert Dürr virtual ~CTLayout( void ); 35*2822fc04SHerbert Dürr 36*2822fc04SHerbert Dürr virtual bool LayoutText( ImplLayoutArgs& ); 37*2822fc04SHerbert Dürr virtual void AdjustLayout( ImplLayoutArgs& ); 38*2822fc04SHerbert Dürr virtual void DrawText( SalGraphics& ) const; 39*2822fc04SHerbert Dürr 40*2822fc04SHerbert Dürr virtual int GetNextGlyphs( int nLen, sal_GlyphId* pOutGlyphIds, Point& rPos, int&, 41*2822fc04SHerbert Dürr sal_Int32* pGlyphAdvances, int* pCharIndexes ) const; 42*2822fc04SHerbert Dürr 43*2822fc04SHerbert Dürr virtual long GetTextWidth() const; 44*2822fc04SHerbert Dürr virtual long FillDXArray( sal_Int32* pDXArray ) const; 45*2822fc04SHerbert Dürr virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const; 46*2822fc04SHerbert Dürr virtual void GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const; 47*2822fc04SHerbert Dürr virtual bool GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const; 48*2822fc04SHerbert Dürr virtual bool GetBoundRect( SalGraphics&, Rectangle& ) const; 49*2822fc04SHerbert Dürr 50*2822fc04SHerbert Dürr const ImplFontData* GetFallbackFontData( sal_GlyphId ) const; 51*2822fc04SHerbert Dürr 52*2822fc04SHerbert Dürr virtual void InitFont( void) const; 53*2822fc04SHerbert Dürr virtual void MoveGlyph( int nStart, long nNewXPos ); 54*2822fc04SHerbert Dürr virtual void DropGlyph( int nStart ); 55*2822fc04SHerbert Dürr virtual void Simplify( bool bIsBase ); 56*2822fc04SHerbert Dürr 57*2822fc04SHerbert Dürr private: 58*2822fc04SHerbert Dürr const CTTextStyle* const mpTextStyle; 59*2822fc04SHerbert Dürr 60*2822fc04SHerbert Dürr // CoreText specific objects 61*2822fc04SHerbert Dürr CFAttributedStringRef mpAttrString; 62*2822fc04SHerbert Dürr CTLineRef mpCTLine; 63*2822fc04SHerbert Dürr 64*2822fc04SHerbert Dürr int mnCharCount; // ==mnEndCharPos-mnMinCharPos 65*2822fc04SHerbert Dürr int mnTrailingSpaces; 66*2822fc04SHerbert Dürr 67*2822fc04SHerbert Dürr // to prevent overflows 68*2822fc04SHerbert Dürr // font requests get size limited by downscaling huge fonts 69*2822fc04SHerbert Dürr // in these cases the font scale becomes something bigger than 1.0 70*2822fc04SHerbert Dürr float mfFontScale; // TODO: does CoreText have a font size limit? 71*2822fc04SHerbert Dürr 72*2822fc04SHerbert Dürr // cached details about the resulting layout 73*2822fc04SHerbert Dürr // mutable members since these details are all lazy initialized 74*2822fc04SHerbert Dürr mutable double mfCachedWidth; // cached value of resulting typographical width 75*2822fc04SHerbert Dürr mutable double mfTrailingSpaceWidth; // in Pixels 76*2822fc04SHerbert Dürr 77*2822fc04SHerbert Dürr // x-offset relative to layout origin 78*2822fc04SHerbert Dürr // currently only used in RTL-layouts 79*2822fc04SHerbert Dürr mutable long mnBaseAdv; 80*2822fc04SHerbert Dürr }; 81*2822fc04SHerbert Dürr 82*2822fc04SHerbert Dürr // ======================================================================= 83*2822fc04SHerbert Dürr 84*2822fc04SHerbert Dürr CTLayout::CTLayout( const CTTextStyle* pTextStyle ) 85*2822fc04SHerbert Dürr : mpTextStyle( pTextStyle ) 86*2822fc04SHerbert Dürr , mpAttrString( NULL ) 87*2822fc04SHerbert Dürr , mpCTLine( NULL ) 88*2822fc04SHerbert Dürr , mnCharCount( 0 ) 89*2822fc04SHerbert Dürr , mnTrailingSpaces( 0 ) 90*2822fc04SHerbert Dürr , mfFontScale( pTextStyle->mfFontScale ) 91*2822fc04SHerbert Dürr , mfCachedWidth( -1 ) 92*2822fc04SHerbert Dürr , mfTrailingSpaceWidth( 0 ) 93*2822fc04SHerbert Dürr , mnBaseAdv( 0 ) 94*2822fc04SHerbert Dürr { 95*2822fc04SHerbert Dürr CFRetain( mpTextStyle->GetStyleDict() ); 96*2822fc04SHerbert Dürr } 97*2822fc04SHerbert Dürr 98*2822fc04SHerbert Dürr // ----------------------------------------------------------------------- 99*2822fc04SHerbert Dürr 100*2822fc04SHerbert Dürr CTLayout::~CTLayout() 101*2822fc04SHerbert Dürr { 102*2822fc04SHerbert Dürr if( mpCTLine ) 103*2822fc04SHerbert Dürr CFRelease( mpCTLine ); 104*2822fc04SHerbert Dürr if( mpAttrString ) 105*2822fc04SHerbert Dürr CFRelease( mpAttrString ); 106*2822fc04SHerbert Dürr CFRelease( mpTextStyle->GetStyleDict() ); 107*2822fc04SHerbert Dürr } 108*2822fc04SHerbert Dürr 109*2822fc04SHerbert Dürr // ----------------------------------------------------------------------- 110*2822fc04SHerbert Dürr 111*2822fc04SHerbert Dürr bool CTLayout::LayoutText( ImplLayoutArgs& rArgs ) 112*2822fc04SHerbert Dürr { 113*2822fc04SHerbert Dürr if( mpAttrString ) 114*2822fc04SHerbert Dürr CFRelease( mpAttrString ); 115*2822fc04SHerbert Dürr mpAttrString = NULL; 116*2822fc04SHerbert Dürr if( mpCTLine ) 117*2822fc04SHerbert Dürr CFRelease( mpCTLine ); 118*2822fc04SHerbert Dürr mpCTLine = NULL; 119*2822fc04SHerbert Dürr 120*2822fc04SHerbert Dürr SalLayout::AdjustLayout( rArgs ); 121*2822fc04SHerbert Dürr mnCharCount = mnEndCharPos - mnMinCharPos; 122*2822fc04SHerbert Dürr 123*2822fc04SHerbert Dürr // short circuit if there is nothing to do 124*2822fc04SHerbert Dürr if( mnCharCount <= 0 ) 125*2822fc04SHerbert Dürr return false; 126*2822fc04SHerbert Dürr 127*2822fc04SHerbert Dürr // create the CoreText line layout 128*2822fc04SHerbert Dürr CFStringRef aCFText = CFStringCreateWithCharactersNoCopy( NULL, rArgs.mpStr + mnMinCharPos, mnCharCount, kCFAllocatorNull ); 129*2822fc04SHerbert Dürr mpAttrString = CFAttributedStringCreate( NULL, aCFText, mpTextStyle->GetStyleDict() ); 130*2822fc04SHerbert Dürr mpCTLine = CTLineCreateWithAttributedString( mpAttrString ); 131*2822fc04SHerbert Dürr CFRelease( aCFText); 132*2822fc04SHerbert Dürr 133*2822fc04SHerbert Dürr // get info about trailing whitespace to prepare for text justification in AdjustLayout() 134*2822fc04SHerbert Dürr mnTrailingSpaces = 0; 135*2822fc04SHerbert Dürr for( int i = mnEndCharPos; --i >= mnMinCharPos; ++mnTrailingSpaces ) 136*2822fc04SHerbert Dürr if( !IsSpacingGlyph( rArgs.mpStr[i] | GF_ISCHAR )) 137*2822fc04SHerbert Dürr break; 138*2822fc04SHerbert Dürr return true; 139*2822fc04SHerbert Dürr } 140*2822fc04SHerbert Dürr 141*2822fc04SHerbert Dürr // ----------------------------------------------------------------------- 142*2822fc04SHerbert Dürr 143*2822fc04SHerbert Dürr void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs ) 144*2822fc04SHerbert Dürr { 145*2822fc04SHerbert Dürr if( !mpCTLine) 146*2822fc04SHerbert Dürr return; 147*2822fc04SHerbert Dürr 148*2822fc04SHerbert Dürr const DynCoreTextSyms& rCT = DynCoreTextSyms::get(); 149*2822fc04SHerbert Dürr // CoreText fills trailing space during justification so we have to 150*2822fc04SHerbert Dürr // take that into account when requesting CT to justify something 151*2822fc04SHerbert Dürr mfTrailingSpaceWidth = rCT.LineGetTrailingWhitespaceWidth( mpCTLine ); 152*2822fc04SHerbert Dürr const int nTrailingSpaceWidth = rint( mfFontScale * mfTrailingSpaceWidth ); 153*2822fc04SHerbert Dürr 154*2822fc04SHerbert Dürr int nOrigWidth = GetTextWidth(); 155*2822fc04SHerbert Dürr int nPixelWidth = rArgs.mnLayoutWidth; 156*2822fc04SHerbert Dürr if( nPixelWidth ) 157*2822fc04SHerbert Dürr { 158*2822fc04SHerbert Dürr nPixelWidth -= nTrailingSpaceWidth; 159*2822fc04SHerbert Dürr if( nPixelWidth <= 0) 160*2822fc04SHerbert Dürr return; 161*2822fc04SHerbert Dürr } 162*2822fc04SHerbert Dürr else if( rArgs.mpDXArray ) 163*2822fc04SHerbert Dürr { 164*2822fc04SHerbert Dürr // for now we are only interested in the layout width 165*2822fc04SHerbert Dürr // TODO: use all mpDXArray elements for layouting 166*2822fc04SHerbert Dürr nPixelWidth = rArgs.mpDXArray[ mnCharCount - 1 - mnTrailingSpaces ]; 167*2822fc04SHerbert Dürr } 168*2822fc04SHerbert Dürr 169*2822fc04SHerbert Dürr // in RTL-layouts trailing spaces are leftmost 170*2822fc04SHerbert Dürr // TODO: use BiDi-algorithm to thoroughly check this assumption 171*2822fc04SHerbert Dürr if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) 172*2822fc04SHerbert Dürr mnBaseAdv = nTrailingSpaceWidth; 173*2822fc04SHerbert Dürr 174*2822fc04SHerbert Dürr // return early if there is nothing to do 175*2822fc04SHerbert Dürr if( nPixelWidth <= 0 ) 176*2822fc04SHerbert Dürr return; 177*2822fc04SHerbert Dürr 178*2822fc04SHerbert Dürr // HACK: justification requests which change the width by just one pixel are probably 179*2822fc04SHerbert Dürr // #i86038# introduced by lossy conversions between integer based coordinate system 180*2822fc04SHerbert Dürr if( (nOrigWidth >= nPixelWidth-1) && (nOrigWidth <= nPixelWidth+1) ) 181*2822fc04SHerbert Dürr return; 182*2822fc04SHerbert Dürr 183*2822fc04SHerbert Dürr // if the text to be justified has whitespace in it then 184*2822fc04SHerbert Dürr // - Writer goes crazy with its HalfSpace magic 185*2822fc04SHerbert Dürr // - LayoutEngine handles spaces specially (in particular at the text start or end) 186*2822fc04SHerbert Dürr if( mnTrailingSpaces ) { 187*2822fc04SHerbert Dürr // adjust for Writer's SwFntObj::DrawText() Halfspace magic at the text end 188*2822fc04SHerbert Dürr std::vector<sal_Int32> aOrigDXAry; 189*2822fc04SHerbert Dürr aOrigDXAry.resize( mnCharCount); 190*2822fc04SHerbert Dürr FillDXArray( &aOrigDXAry[0] ); 191*2822fc04SHerbert Dürr int nLastCharSpace = rArgs.mpDXArray[ mnCharCount-1-mnTrailingSpaces ] 192*2822fc04SHerbert Dürr - aOrigDXAry[ mnCharCount-1-mnTrailingSpaces ]; 193*2822fc04SHerbert Dürr nPixelWidth -= nLastCharSpace; 194*2822fc04SHerbert Dürr if( nPixelWidth < 0 ) 195*2822fc04SHerbert Dürr return; 196*2822fc04SHerbert Dürr // recreate the CoreText line layout without trailing spaces 197*2822fc04SHerbert Dürr CFRelease( mpCTLine ); 198*2822fc04SHerbert Dürr CFStringRef aCFText = CFStringCreateWithCharactersNoCopy( NULL, rArgs.mpStr + mnMinCharPos, 199*2822fc04SHerbert Dürr mnCharCount - mnTrailingSpaces, kCFAllocatorNull ); 200*2822fc04SHerbert Dürr CFAttributedStringRef pAttrStr = CFAttributedStringCreate( NULL, aCFText, mpTextStyle->GetStyleDict() ); 201*2822fc04SHerbert Dürr mpCTLine = CTLineCreateWithAttributedString( pAttrStr ); 202*2822fc04SHerbert Dürr CFRelease( aCFText); 203*2822fc04SHerbert Dürr CFRelease( pAttrStr ); 204*2822fc04SHerbert Dürr } 205*2822fc04SHerbert Dürr 206*2822fc04SHerbert Dürr CTLineRef pNewCTLine = rCT.LineCreateJustifiedLine( mpCTLine, 1.0, nPixelWidth / mfFontScale ); 207*2822fc04SHerbert Dürr if( !pNewCTLine ) { // CTLineCreateJustifiedLine can and does fail 208*2822fc04SHerbert Dürr // handle failure by keeping the unjustified layout 209*2822fc04SHerbert Dürr // TODO: a better solution such as 210*2822fc04SHerbert Dürr // - forcing glyph overlap 211*2822fc04SHerbert Dürr // - changing the font size 212*2822fc04SHerbert Dürr // - changing the CTM matrix 213*2822fc04SHerbert Dürr return; 214*2822fc04SHerbert Dürr } 215*2822fc04SHerbert Dürr CFRelease( mpCTLine ); 216*2822fc04SHerbert Dürr mpCTLine = pNewCTLine; 217*2822fc04SHerbert Dürr mfCachedWidth = -1; // TODO: can we set it directly to target width we requested? For now we re-measure 218*2822fc04SHerbert Dürr mfTrailingSpaceWidth = 0; 219*2822fc04SHerbert Dürr } 220*2822fc04SHerbert Dürr 221*2822fc04SHerbert Dürr // ----------------------------------------------------------------------- 222*2822fc04SHerbert Dürr 223*2822fc04SHerbert Dürr void CTLayout::DrawText( SalGraphics& rGraphics ) const 224*2822fc04SHerbert Dürr { 225*2822fc04SHerbert Dürr AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics); 226*2822fc04SHerbert Dürr 227*2822fc04SHerbert Dürr // short circuit if there is nothing to do 228*2822fc04SHerbert Dürr if( (mnCharCount <= 0) 229*2822fc04SHerbert Dürr || !rAquaGraphics.CheckContext() ) 230*2822fc04SHerbert Dürr return; 231*2822fc04SHerbert Dürr 232*2822fc04SHerbert Dürr // the view is vertically flipped => flipped glyphs 233*2822fc04SHerbert Dürr // so apply a temporary transformation that it flips back 234*2822fc04SHerbert Dürr // also compensate if the font was size limited 235*2822fc04SHerbert Dürr CGContextSaveGState( rAquaGraphics.mrContext ); 236*2822fc04SHerbert Dürr CGContextScaleCTM( rAquaGraphics.mrContext, +mfFontScale, -mfFontScale ); 237*2822fc04SHerbert Dürr CGContextSetShouldAntialias( rAquaGraphics.mrContext, !rAquaGraphics.mbNonAntialiasedText ); 238*2822fc04SHerbert Dürr 239*2822fc04SHerbert Dürr // Draw the text 240*2822fc04SHerbert Dürr const Point aVclPos = GetDrawPosition( Point(mnBaseAdv,0) ); 241*2822fc04SHerbert Dürr CGPoint aTextPos = { +aVclPos.X()/mfFontScale, -aVclPos.Y()/mfFontScale }; 242*2822fc04SHerbert Dürr 243*2822fc04SHerbert Dürr if( mpTextStyle->mfFontRotation != 0.0 ) 244*2822fc04SHerbert Dürr { 245*2822fc04SHerbert Dürr const CGFloat fRadians = mpTextStyle->mfFontRotation; 246*2822fc04SHerbert Dürr CGContextRotateCTM( rAquaGraphics.mrContext, +fRadians ); 247*2822fc04SHerbert Dürr 248*2822fc04SHerbert Dürr const CGAffineTransform aInvMatrix = CGAffineTransformMakeRotation( -fRadians ); 249*2822fc04SHerbert Dürr aTextPos = CGPointApplyAffineTransform( aTextPos, aInvMatrix ); 250*2822fc04SHerbert Dürr } 251*2822fc04SHerbert Dürr 252*2822fc04SHerbert Dürr CGContextSetTextPosition( rAquaGraphics.mrContext, aTextPos.x, aTextPos.y ); 253*2822fc04SHerbert Dürr CTLineDraw( mpCTLine, rAquaGraphics.mrContext ); 254*2822fc04SHerbert Dürr 255*2822fc04SHerbert Dürr // request an update of the changed window area 256*2822fc04SHerbert Dürr if( rAquaGraphics.IsWindowGraphics() ) 257*2822fc04SHerbert Dürr { 258*2822fc04SHerbert Dürr const CGRect aInkRect = CTLineGetImageBounds( mpCTLine, rAquaGraphics.mrContext ); 259*2822fc04SHerbert Dürr const CGRect aRefreshRect = CGContextConvertRectToDeviceSpace( rAquaGraphics.mrContext, aInkRect ); 260*2822fc04SHerbert Dürr rAquaGraphics.RefreshRect( aRefreshRect ); 261*2822fc04SHerbert Dürr } 262*2822fc04SHerbert Dürr 263*2822fc04SHerbert Dürr // restore the original graphic context transformations 264*2822fc04SHerbert Dürr CGContextRestoreGState( rAquaGraphics.mrContext ); 265*2822fc04SHerbert Dürr } 266*2822fc04SHerbert Dürr 267*2822fc04SHerbert Dürr // ----------------------------------------------------------------------- 268*2822fc04SHerbert Dürr 269*2822fc04SHerbert Dürr int CTLayout::GetNextGlyphs( int nLen, sal_GlyphId* pOutGlyphIds, Point& rPos, int& nStart, 270*2822fc04SHerbert Dürr sal_Int32* pGlyphAdvances, int* pCharIndexes ) const 271*2822fc04SHerbert Dürr { 272*2822fc04SHerbert Dürr if( !mpCTLine ) 273*2822fc04SHerbert Dürr return 0; 274*2822fc04SHerbert Dürr 275*2822fc04SHerbert Dürr if( nStart < 0 ) // first glyph requested? 276*2822fc04SHerbert Dürr nStart = 0; 277*2822fc04SHerbert Dürr nLen = 1; // TODO: handle nLen>1 below 278*2822fc04SHerbert Dürr 279*2822fc04SHerbert Dürr // prepare to iterate over the glyph runs 280*2822fc04SHerbert Dürr int nCount = 0; 281*2822fc04SHerbert Dürr int nSubIndex = nStart; 282*2822fc04SHerbert Dürr 283*2822fc04SHerbert Dürr const DynCoreTextSyms& rCT = DynCoreTextSyms::get(); 284*2822fc04SHerbert Dürr typedef std::vector<CGGlyph> CGGlyphVector; 285*2822fc04SHerbert Dürr typedef std::vector<CGPoint> CGPointVector; 286*2822fc04SHerbert Dürr typedef std::vector<CGSize> CGSizeVector; 287*2822fc04SHerbert Dürr typedef std::vector<CFIndex> CFIndexVector; 288*2822fc04SHerbert Dürr CGGlyphVector aCGGlyphVec; 289*2822fc04SHerbert Dürr CGPointVector aCGPointVec; 290*2822fc04SHerbert Dürr CGSizeVector aCGSizeVec; 291*2822fc04SHerbert Dürr CFIndexVector aCFIndexVec; 292*2822fc04SHerbert Dürr 293*2822fc04SHerbert Dürr // TODO: iterate over cached layout 294*2822fc04SHerbert Dürr CFArrayRef aGlyphRuns = rCT.LineGetGlyphRuns( mpCTLine ); 295*2822fc04SHerbert Dürr const int nRunCount = CFArrayGetCount( aGlyphRuns ); 296*2822fc04SHerbert Dürr for( int nRunIndex = 0; nRunIndex < nRunCount; ++nRunIndex ) { 297*2822fc04SHerbert Dürr CTRunRef pGlyphRun = (CTRunRef)CFArrayGetValueAtIndex( aGlyphRuns, nRunIndex ); 298*2822fc04SHerbert Dürr const CFIndex nGlyphsInRun = rCT.RunGetGlyphCount( pGlyphRun ); 299*2822fc04SHerbert Dürr // skip to the first glyph run of interest 300*2822fc04SHerbert Dürr if( nSubIndex >= nGlyphsInRun ) { 301*2822fc04SHerbert Dürr nSubIndex -= nGlyphsInRun; 302*2822fc04SHerbert Dürr continue; 303*2822fc04SHerbert Dürr } 304*2822fc04SHerbert Dürr const CFRange aFullRange = CFRangeMake( 0, nGlyphsInRun ); 305*2822fc04SHerbert Dürr 306*2822fc04SHerbert Dürr // get glyph run details 307*2822fc04SHerbert Dürr const CGGlyph* pCGGlyphIdx = rCT.RunGetGlyphsPtr( pGlyphRun ); 308*2822fc04SHerbert Dürr if( !pCGGlyphIdx ) { 309*2822fc04SHerbert Dürr aCGGlyphVec.reserve( nGlyphsInRun ); 310*2822fc04SHerbert Dürr CTRunGetGlyphs( pGlyphRun, aFullRange, &aCGGlyphVec[0] ); 311*2822fc04SHerbert Dürr pCGGlyphIdx = &aCGGlyphVec[0]; 312*2822fc04SHerbert Dürr } 313*2822fc04SHerbert Dürr const CGPoint* pCGGlyphPos = rCT.RunGetPositionsPtr( pGlyphRun ); 314*2822fc04SHerbert Dürr if( !pCGGlyphPos ) { 315*2822fc04SHerbert Dürr aCGPointVec.reserve( nGlyphsInRun ); 316*2822fc04SHerbert Dürr CTRunGetPositions( pGlyphRun, aFullRange, &aCGPointVec[0] ); 317*2822fc04SHerbert Dürr pCGGlyphPos = &aCGPointVec[0]; 318*2822fc04SHerbert Dürr } 319*2822fc04SHerbert Dürr 320*2822fc04SHerbert Dürr const CGSize* pCGGlyphAdvs = NULL; 321*2822fc04SHerbert Dürr if( pGlyphAdvances) { 322*2822fc04SHerbert Dürr pCGGlyphAdvs = rCT.RunGetAdvancesPtr( pGlyphRun ); 323*2822fc04SHerbert Dürr if( !pCGGlyphAdvs) { 324*2822fc04SHerbert Dürr aCGSizeVec.reserve( nGlyphsInRun ); 325*2822fc04SHerbert Dürr CTRunGetAdvances( pGlyphRun, aFullRange, &aCGSizeVec[0] ); 326*2822fc04SHerbert Dürr pCGGlyphAdvs = &aCGSizeVec[0]; 327*2822fc04SHerbert Dürr } 328*2822fc04SHerbert Dürr } 329*2822fc04SHerbert Dürr 330*2822fc04SHerbert Dürr const CFIndex* pCGGlyphStrIdx = NULL; 331*2822fc04SHerbert Dürr if( pCharIndexes) { 332*2822fc04SHerbert Dürr pCGGlyphStrIdx = rCT.RunGetStringIndicesPtr( pGlyphRun ); 333*2822fc04SHerbert Dürr if( !pCGGlyphStrIdx) { 334*2822fc04SHerbert Dürr aCFIndexVec.reserve( nGlyphsInRun ); 335*2822fc04SHerbert Dürr CTRunGetStringIndices( pGlyphRun, aFullRange, &aCFIndexVec[0] ); 336*2822fc04SHerbert Dürr pCGGlyphStrIdx = &aCFIndexVec[0]; 337*2822fc04SHerbert Dürr } 338*2822fc04SHerbert Dürr } 339*2822fc04SHerbert Dürr 340*2822fc04SHerbert Dürr // get the details for each interesting glyph 341*2822fc04SHerbert Dürr // TODO: handle nLen>1 342*2822fc04SHerbert Dürr for(; (--nLen >= 0) && (nSubIndex < nGlyphsInRun); ++nSubIndex, ++nStart ) 343*2822fc04SHerbert Dürr { 344*2822fc04SHerbert Dürr // convert glyph details for VCL 345*2822fc04SHerbert Dürr *(pOutGlyphIds++) = pCGGlyphIdx[ nSubIndex ]; 346*2822fc04SHerbert Dürr if( pGlyphAdvances ) 347*2822fc04SHerbert Dürr *(pGlyphAdvances++) = pCGGlyphAdvs[ nSubIndex ].width; 348*2822fc04SHerbert Dürr if( pCharIndexes ) 349*2822fc04SHerbert Dürr *(pCharIndexes++) = pCGGlyphStrIdx[ nSubIndex] + mnMinCharPos; 350*2822fc04SHerbert Dürr if( !nCount++ ) { 351*2822fc04SHerbert Dürr const CGPoint& rCurPos = pCGGlyphPos[ nSubIndex ]; 352*2822fc04SHerbert Dürr rPos = GetDrawPosition( Point( mfFontScale * rCurPos.x, mfFontScale * rCurPos.y) ); 353*2822fc04SHerbert Dürr } 354*2822fc04SHerbert Dürr } 355*2822fc04SHerbert Dürr nSubIndex = 0; // prepare for the next glyph run 356*2822fc04SHerbert Dürr break; // TODO: handle nLen>1 357*2822fc04SHerbert Dürr } 358*2822fc04SHerbert Dürr 359*2822fc04SHerbert Dürr return nCount; 360*2822fc04SHerbert Dürr } 361*2822fc04SHerbert Dürr 362*2822fc04SHerbert Dürr // ----------------------------------------------------------------------- 363*2822fc04SHerbert Dürr 364*2822fc04SHerbert Dürr long CTLayout::GetTextWidth() const 365*2822fc04SHerbert Dürr { 366*2822fc04SHerbert Dürr if( (mnCharCount <= 0) || !mpCTLine ) 367*2822fc04SHerbert Dürr return 0; 368*2822fc04SHerbert Dürr 369*2822fc04SHerbert Dürr if( mfCachedWidth < 0.0 ) 370*2822fc04SHerbert Dürr mfCachedWidth = CTLineGetTypographicBounds( mpCTLine, NULL, NULL, NULL ); 371*2822fc04SHerbert Dürr 372*2822fc04SHerbert Dürr const long nScaledWidth = lrint( mfFontScale * mfCachedWidth ); 373*2822fc04SHerbert Dürr return nScaledWidth; 374*2822fc04SHerbert Dürr } 375*2822fc04SHerbert Dürr 376*2822fc04SHerbert Dürr // ----------------------------------------------------------------------- 377*2822fc04SHerbert Dürr 378*2822fc04SHerbert Dürr long CTLayout::FillDXArray( sal_Int32* pDXArray ) const 379*2822fc04SHerbert Dürr { 380*2822fc04SHerbert Dürr // short circuit requests which don't need full details 381*2822fc04SHerbert Dürr if( !pDXArray ) 382*2822fc04SHerbert Dürr return GetTextWidth(); 383*2822fc04SHerbert Dürr 384*2822fc04SHerbert Dürr long nPixWidth = GetTextWidth(); 385*2822fc04SHerbert Dürr if( pDXArray ) { 386*2822fc04SHerbert Dürr // initialize the result array 387*2822fc04SHerbert Dürr for( int i = 0; i < mnCharCount; ++i) 388*2822fc04SHerbert Dürr pDXArray[i] = 0; 389*2822fc04SHerbert Dürr // handle each glyph run 390*2822fc04SHerbert Dürr CFArrayRef aGlyphRuns = CTLineGetGlyphRuns( mpCTLine ); 391*2822fc04SHerbert Dürr const int nRunCount = CFArrayGetCount( aGlyphRuns ); 392*2822fc04SHerbert Dürr typedef std::vector<CGSize> CGSizeVector; 393*2822fc04SHerbert Dürr CGSizeVector aSizeVec; 394*2822fc04SHerbert Dürr typedef std::vector<CFIndex> CFIndexVector; 395*2822fc04SHerbert Dürr CFIndexVector aIndexVec; 396*2822fc04SHerbert Dürr for( int nRunIndex = 0; nRunIndex < nRunCount; ++nRunIndex ) { 397*2822fc04SHerbert Dürr CTRunRef pGlyphRun = (CTRunRef)CFArrayGetValueAtIndex( aGlyphRuns, nRunIndex ); 398*2822fc04SHerbert Dürr const CFIndex nGlyphCount = CTRunGetGlyphCount( pGlyphRun ); 399*2822fc04SHerbert Dürr const CFRange aFullRange = CFRangeMake( 0, nGlyphCount ); 400*2822fc04SHerbert Dürr aSizeVec.reserve( nGlyphCount ); 401*2822fc04SHerbert Dürr aIndexVec.reserve( nGlyphCount ); 402*2822fc04SHerbert Dürr CTRunGetAdvances( pGlyphRun, aFullRange, &aSizeVec[0] ); 403*2822fc04SHerbert Dürr CTRunGetStringIndices( pGlyphRun, aFullRange, &aIndexVec[0] ); 404*2822fc04SHerbert Dürr for( int i = 0; i != nGlyphCount; ++i ) { 405*2822fc04SHerbert Dürr const int nRelIdx = aIndexVec[i]; 406*2822fc04SHerbert Dürr pDXArray[ nRelIdx ] += aSizeVec[i].width; 407*2822fc04SHerbert Dürr } 408*2822fc04SHerbert Dürr } 409*2822fc04SHerbert Dürr } 410*2822fc04SHerbert Dürr 411*2822fc04SHerbert Dürr return nPixWidth; 412*2822fc04SHerbert Dürr } 413*2822fc04SHerbert Dürr 414*2822fc04SHerbert Dürr // ----------------------------------------------------------------------- 415*2822fc04SHerbert Dürr 416*2822fc04SHerbert Dürr int CTLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const 417*2822fc04SHerbert Dürr { 418*2822fc04SHerbert Dürr if( !mpCTLine ) 419*2822fc04SHerbert Dürr return STRING_LEN; 420*2822fc04SHerbert Dürr 421*2822fc04SHerbert Dürr CTTypesetterRef aCTTypeSetter = CTTypesetterCreateWithAttributedString( mpAttrString ); 422*2822fc04SHerbert Dürr const double fCTMaxWidth = (double)nMaxWidth / (nFactor * mfFontScale); 423*2822fc04SHerbert Dürr CFIndex nIndex = CTTypesetterSuggestClusterBreak( aCTTypeSetter, 0, fCTMaxWidth ); 424*2822fc04SHerbert Dürr if( nIndex >= mnCharCount ) 425*2822fc04SHerbert Dürr return STRING_LEN; 426*2822fc04SHerbert Dürr 427*2822fc04SHerbert Dürr nIndex += mnMinCharPos; 428*2822fc04SHerbert Dürr return (int)nIndex; 429*2822fc04SHerbert Dürr } 430*2822fc04SHerbert Dürr 431*2822fc04SHerbert Dürr // ----------------------------------------------------------------------- 432*2822fc04SHerbert Dürr 433*2822fc04SHerbert Dürr void CTLayout::GetCaretPositions( int nMaxIndex, sal_Int32* pCaretXArray ) const 434*2822fc04SHerbert Dürr { 435*2822fc04SHerbert Dürr DBG_ASSERT( ((nMaxIndex>0)&&!(nMaxIndex&1)), 436*2822fc04SHerbert Dürr "CTLayout::GetCaretPositions() : invalid number of caret pairs requested"); 437*2822fc04SHerbert Dürr 438*2822fc04SHerbert Dürr // initialize the caret positions 439*2822fc04SHerbert Dürr for( int i = 0; i < nMaxIndex; ++i ) 440*2822fc04SHerbert Dürr pCaretXArray[ i ] = -1; 441*2822fc04SHerbert Dürr 442*2822fc04SHerbert Dürr const DynCoreTextSyms& rCT = DynCoreTextSyms::get(); 443*2822fc04SHerbert Dürr for( int n = 0; n <= mnCharCount; ++n ) 444*2822fc04SHerbert Dürr { 445*2822fc04SHerbert Dürr // measure the characters cursor position 446*2822fc04SHerbert Dürr CGFloat fPos2 = -1; 447*2822fc04SHerbert Dürr const CGFloat fPos1 = rCT.LineGetOffsetForStringIndex( mpCTLine, n, &fPos2 ); 448*2822fc04SHerbert Dürr (void)fPos2; // TODO: split cursor at line direction change 449*2822fc04SHerbert Dürr // update previous trailing position 450*2822fc04SHerbert Dürr if( n > 0 ) 451*2822fc04SHerbert Dürr pCaretXArray[ 2*n-1 ] = lrint( fPos1 * mfFontScale ); 452*2822fc04SHerbert Dürr // update current leading position 453*2822fc04SHerbert Dürr if( 2*n >= nMaxIndex ) 454*2822fc04SHerbert Dürr break; 455*2822fc04SHerbert Dürr pCaretXArray[ 2*n+0 ] = lrint( fPos1 * mfFontScale ); 456*2822fc04SHerbert Dürr } 457*2822fc04SHerbert Dürr } 458*2822fc04SHerbert Dürr 459*2822fc04SHerbert Dürr // ----------------------------------------------------------------------- 460*2822fc04SHerbert Dürr 461*2822fc04SHerbert Dürr bool CTLayout::GetBoundRect( SalGraphics& rGraphics, Rectangle& rVCLRect ) const 462*2822fc04SHerbert Dürr { 463*2822fc04SHerbert Dürr AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics); 464*2822fc04SHerbert Dürr CGRect aMacRect = CTLineGetImageBounds( mpCTLine, rAquaGraphics.mrContext ); 465*2822fc04SHerbert Dürr CGPoint aMacPos = CGContextGetTextPosition( rAquaGraphics.mrContext ); 466*2822fc04SHerbert Dürr aMacRect.origin.x -= aMacPos.x; 467*2822fc04SHerbert Dürr aMacRect.origin.y -= aMacPos.y; 468*2822fc04SHerbert Dürr 469*2822fc04SHerbert Dürr const Point aPos = GetDrawPosition( Point(mnBaseAdv, 0) ); 470*2822fc04SHerbert Dürr 471*2822fc04SHerbert Dürr // CoreText top-bottom are vertically flipped from a VCL aspect 472*2822fc04SHerbert Dürr rVCLRect.Left() = aPos.X() + mfFontScale * aMacRect.origin.x; 473*2822fc04SHerbert Dürr rVCLRect.Right() = aPos.X() + mfFontScale * (aMacRect.origin.x + aMacRect.size.width); 474*2822fc04SHerbert Dürr rVCLRect.Bottom() = aPos.Y() - mfFontScale * aMacRect.origin.y; 475*2822fc04SHerbert Dürr rVCLRect.Top() = aPos.Y() - mfFontScale * (aMacRect.origin.y + aMacRect.size.height); 476*2822fc04SHerbert Dürr return true; 477*2822fc04SHerbert Dürr } 478*2822fc04SHerbert Dürr 479*2822fc04SHerbert Dürr // ======================================================================= 480*2822fc04SHerbert Dürr 481*2822fc04SHerbert Dürr // glyph fallback is supported directly by Aqua 482*2822fc04SHerbert Dürr // so methods used only by MultiSalLayout can be dummy implementated 483*2822fc04SHerbert Dürr bool CTLayout::GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const { return false; } 484*2822fc04SHerbert Dürr void CTLayout::InitFont() const {} 485*2822fc04SHerbert Dürr void CTLayout::MoveGlyph( int /*nStart*/, long /*nNewXPos*/ ) {} 486*2822fc04SHerbert Dürr void CTLayout::DropGlyph( int /*nStart*/ ) {} 487*2822fc04SHerbert Dürr void CTLayout::Simplify( bool /*bIsBase*/ ) {} 488*2822fc04SHerbert Dürr 489*2822fc04SHerbert Dürr // get the ImplFontData for a glyph fallback font 490*2822fc04SHerbert Dürr // for a glyphid that was returned by CTLayout::GetNextGlyphs() 491*2822fc04SHerbert Dürr const ImplFontData* CTLayout::GetFallbackFontData( sal_GlyphId /*aGlyphId*/ ) const 492*2822fc04SHerbert Dürr { 493*2822fc04SHerbert Dürr #if 0 494*2822fc04SHerbert Dürr // check if any fallback fonts were needed 495*2822fc04SHerbert Dürr if( !mpFallbackInfo ) 496*2822fc04SHerbert Dürr return NULL; 497*2822fc04SHerbert Dürr // check if the current glyph needs a fallback font 498*2822fc04SHerbert Dürr int nFallbackLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT; 499*2822fc04SHerbert Dürr if( !nFallbackLevel ) 500*2822fc04SHerbert Dürr return NULL; 501*2822fc04SHerbert Dürr pFallbackFont = mpFallbackInfo->GetFallbackFontData( nFallbackLevel ); 502*2822fc04SHerbert Dürr #else 503*2822fc04SHerbert Dürr // let CoreText's font cascading handle glyph fallback 504*2822fc04SHerbert Dürr const ImplFontData* pFallbackFont = NULL; 505*2822fc04SHerbert Dürr #endif 506*2822fc04SHerbert Dürr return pFallbackFont; 507*2822fc04SHerbert Dürr } 508*2822fc04SHerbert Dürr 509*2822fc04SHerbert Dürr // ======================================================================= 510*2822fc04SHerbert Dürr 511*2822fc04SHerbert Dürr SalLayout* CTTextStyle::GetTextLayout( void ) const 512*2822fc04SHerbert Dürr { 513*2822fc04SHerbert Dürr return new CTLayout( this); 514*2822fc04SHerbert Dürr } 515*2822fc04SHerbert Dürr 516*2822fc04SHerbert Dürr // ======================================================================= 517*2822fc04SHerbert Dürr 518