Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / vcl / quartz / ctlayout.cxx
blob0b29673cbf42c3eb42a60811879c62a66b41ce45
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/types.h>
21 #include <boost/ptr_container/ptr_vector.hpp>
22 #include "tools/debug.hxx"
24 #include "ctfonts.hxx"
25 #include "CTRunData.hxx"
28 class CTLayout : public SalLayout
30 public:
31 explicit CTLayout( const CoreTextStyle* );
32 virtual ~CTLayout( void );
34 virtual bool LayoutText( ImplLayoutArgs& ) SAL_OVERRIDE;
35 virtual void AdjustLayout( ImplLayoutArgs& ) SAL_OVERRIDE;
36 virtual void DrawText( SalGraphics& ) const SAL_OVERRIDE;
37 virtual bool DrawTextSpecial( SalGraphics& rGraphics, sal_uInt32 flags ) const SAL_OVERRIDE;
39 virtual int GetNextGlyphs( int nLen, sal_GlyphId* pOutGlyphIds, Point& rPos, int&,
40 sal_Int32* pGlyphAdvances, int* pCharIndexes,
41 const PhysicalFontFace** pFallbackFonts ) const SAL_OVERRIDE;
43 virtual long GetTextWidth() const SAL_OVERRIDE;
44 virtual long FillDXArray( sal_Int32* pDXArray ) const SAL_OVERRIDE;
45 virtual sal_Int32 GetTextBreak(long nMaxWidth, long nCharExtra, int nFactor) const SAL_OVERRIDE;
46 virtual void GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const SAL_OVERRIDE;
47 virtual bool GetBoundRect( SalGraphics&, Rectangle& ) const SAL_OVERRIDE;
49 virtual void InitFont( void) const SAL_OVERRIDE;
50 virtual void MoveGlyph( int nStart, long nNewXPos ) SAL_OVERRIDE;
51 virtual void DropGlyph( int nStart ) SAL_OVERRIDE;
52 virtual void Simplify( bool bIsBase ) SAL_OVERRIDE;
54 private:
55 void drawCTLine(AquaSalGraphics& rAquaGraphics, CTLineRef ctline, const CoreTextStyle* const pStyle) const;
56 CGPoint GetTextDrawPosition(void) const;
57 double GetWidth(void) const;
58 bool CacheGlyphLayout(void) const;
60 const CoreTextStyle* const mpTextStyle;
62 // CoreText specific objects
63 CFAttributedStringRef mpAttrString;
64 CTLineRef mpCTLine;
66 int mnCharCount; // ==mnEndCharPos-mnMinCharPos
67 int mnTrailingSpaceCount;
68 double mfTrailingSpaceWidth;
70 // cached details about the resulting layout
71 // mutable members since these details are all lazy initialized
72 mutable double mfCachedWidth; // cached value of resulting typographical width
74 // x-offset relative to layout origin
75 // currently only used in RTL-layouts
76 mutable double mfBaseAdv;
78 mutable bool bLayouted; // true if the glyph layout information are cached and current;
79 mutable boost::ptr_vector<CTRunData> m_vRunData;
83 CTLayout::CTLayout( const CoreTextStyle* pTextStyle )
84 : mpTextStyle( pTextStyle )
85 , mpAttrString( NULL )
86 , mpCTLine( NULL )
87 , mnCharCount( 0 )
88 , mnTrailingSpaceCount( 0 )
89 , mfTrailingSpaceWidth( 0.0 )
90 , mfCachedWidth( -1 )
91 , mfBaseAdv( 0 )
92 , bLayouted( false )
96 CTLayout::~CTLayout()
98 if( mpCTLine )
99 CFRelease( mpCTLine );
100 if( mpAttrString )
101 CFRelease( mpAttrString );
104 bool CTLayout::LayoutText( ImplLayoutArgs& rArgs )
106 m_vRunData.release();
107 bLayouted = false;
109 if( mpAttrString )
110 CFRelease( mpAttrString );
111 mpAttrString = NULL;
112 if( mpCTLine )
113 CFRelease( mpCTLine );
114 mpCTLine = NULL;
116 SalLayout::AdjustLayout( rArgs );
117 mnCharCount = mnEndCharPos - mnMinCharPos;
119 // short circuit if there is nothing to do
120 if( mnCharCount <= 0 )
121 return false;
123 // create the CoreText line layout
124 CFStringRef aCFText = CFStringCreateWithCharactersNoCopy( NULL,
125 rArgs.mpStr + mnMinCharPos,
126 mnCharCount,
127 kCFAllocatorNull );
128 // CFAttributedStringCreate copies the attribues parameter
129 mpAttrString = CFAttributedStringCreate( NULL, aCFText, mpTextStyle->GetStyleDict() );
130 mpCTLine = CTLineCreateWithAttributedString( mpAttrString );
131 CFRelease( aCFText);
133 mnTrailingSpaceCount = 0;
134 // reverse search for first 'non-space'...
135 for( int i = mnEndCharPos - 1; i >= mnMinCharPos; i--)
137 sal_Unicode nChar = rArgs.mpStr[i];
138 if ((nChar <= 0x0020) || // blank
139 (nChar == 0x00A0) || // non breaking space
140 (nChar >= 0x2000 && nChar <= 0x200F) || // whitespace
141 (nChar == 0x3000)) // ideographic space
143 mnTrailingSpaceCount += 1;
145 else
147 break;
150 return true;
153 void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs )
155 if( !mpCTLine)
156 return;
158 int nPixelWidth = rArgs.mpDXArray ? rArgs.mpDXArray[ mnCharCount - 1 ] : rArgs.mnLayoutWidth;
159 if( nPixelWidth <= 0)
160 return;
162 // HACK: justification requests which change the width by just one pixel are probably
163 // #i86038# introduced by lossy conversions between integer based coordinate system
164 int fuzz = (nPixelWidth - GetTextWidth()) / 2;
165 if (!fuzz)
167 return;
170 // if the text to be justified has whitespace in it then
171 // - Writer goes crazy with its HalfSpace magic
172 // - CoreText handles spaces specially (in particular at the text end)
173 if( mnTrailingSpaceCount )
175 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
176 // don't recreate line layout here, because this can lead to problems
177 // (looks like internal issues inside early CoreText versions)
178 mfTrailingSpaceWidth = CTLineGetTrailingWhitespaceWidth( mpCTLine );
179 #else
180 if(rArgs.mpDXArray)
182 int nFullPixelWidth = nPixelWidth;
183 nPixelWidth = mnTrailingSpaceCount == mnCharCount
184 ? 0 : rArgs.mpDXArray[ mnCharCount - mnTrailingSpaceCount - 1];
185 mfTrailingSpaceWidth = nFullPixelWidth - nPixelWidth;
187 else
189 if(mfTrailingSpaceWidth <= 0.0)
191 mfTrailingSpaceWidth = CTLineGetTrailingWhitespaceWidth( mpCTLine );
192 nPixelWidth -= rint(mfTrailingSpaceWidth);
195 if(nPixelWidth <= 0)
197 return;
199 // recreate the CoreText line layout without trailing spaces
200 CFRelease( mpCTLine );
201 CFStringRef aCFText = CFStringCreateWithCharactersNoCopy( NULL,
202 rArgs.mpStr + mnMinCharPos,
203 mnCharCount - mnTrailingSpaceCount,
204 kCFAllocatorNull );
205 CFAttributedStringRef pAttrStr = CFAttributedStringCreate( NULL,
206 aCFText,
207 mpTextStyle->GetStyleDict() );
208 mpCTLine = CTLineCreateWithAttributedString( pAttrStr );
209 CFRelease( pAttrStr );
210 CFRelease( aCFText );
211 #endif
213 // in RTL-layouts trailing spaces are leftmost
214 // TODO: use BiDi-algorithm to thoroughly check this assumption
215 if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL)
217 mfBaseAdv = mfTrailingSpaceWidth;
221 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
222 CTLineRef pNewCTLine = CTLineCreateJustifiedLine( mpCTLine, 1.0, nPixelWidth - mfTrailingSpaceWidth );
223 #else
224 CTLineRef pNewCTLine = CTLineCreateJustifiedLine( mpCTLine, 1.0, nPixelWidth);
225 #endif
226 if( !pNewCTLine )
228 // CTLineCreateJustifiedLine can and does fail
229 // handle failure by keeping the unjustified layout
230 // TODO: a better solution such as
231 // - forcing glyph overlap
232 // - changing the font size
233 // - changing the CTM matrix
234 return;
236 CFRelease( mpCTLine );
237 mpCTLine = pNewCTLine;
238 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
239 mfCachedWidth = nPixelWidth;
240 #else
241 mfCachedWidth = nPixelWidth + mfTrailingSpaceWidth;
242 #endif
245 // When drawing right aligned text, rounding errors in the position returned by
246 // GetDrawPosition() cause the right margin of the text to change whenever text
247 // width changes causing "jumping letters" effect. So here we calculate the
248 // drawing position relative to the right margin on our own to avoid the
249 // rounding errors. That is basically a hack, and it should go away if one day
250 // we managed to get rid of those rounding errors.
252 // We continue using GetDrawPosition() for non-right aligned text, to minimize
253 // any unforeseen side effects.
254 CGPoint CTLayout::GetTextDrawPosition(void) const
256 CGFloat fPosX, fPosY;
258 if (mnLayoutFlags & SAL_LAYOUT_RIGHT_ALIGN)
260 // text is always drawn at its leftmost point
261 const Point aPos = DrawBase();
262 fPosX = aPos.X() + mfBaseAdv - GetWidth();
263 fPosY = aPos.Y();
265 else
267 const Point aPos = GetDrawPosition(Point(mfBaseAdv, 0));
268 fPosX = aPos.X();
269 fPosY = aPos.Y();
272 CGPoint aTextPos = { +fPosX, -fPosY };
273 return aTextPos;
276 /* use to deal with special font decoration like 'outline' drawing
277 * return true if it was able to handle the drawing
278 * false if not, in which case the caller
279 * is supposed to fallback to 'generic' method
281 bool CTLayout::DrawTextSpecial( SalGraphics& rGraphics, sal_uInt32 flags ) const
283 AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics);
285 // short circuit if there is nothing to do
286 if( (mnCharCount <= 0) || !rAquaGraphics.CheckContext() )
287 return true;
289 if (flags & DRAWTEXT_F_OUTLINE)
291 CFMutableDictionaryRef styledict = CFDictionaryCreateMutableCopy(
292 CFAllocatorGetDefault(),
293 CFDictionaryGetCount(mpTextStyle->GetStyleDict()),
294 mpTextStyle->GetStyleDict());
296 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
297 /* just don't do 'kCTStrokeWidthAttributeName' */
298 #else
299 int nStroke = 2;
300 CFNumberRef rStroke = CFNumberCreate(NULL, kCFNumberSInt32Type, &nStroke);
301 CFDictionarySetValue(styledict, kCTStrokeWidthAttributeName, rStroke);
302 #endif
304 CFAttributedStringRef pAttrStr = CFAttributedStringCreate(
305 NULL,
306 CFAttributedStringGetString(mpAttrString),
307 styledict);
308 CTLineRef pCTLine = CTLineCreateWithAttributedString( pAttrStr );
309 CFRelease( pAttrStr );
311 /* draw the text in 'outline' */
312 drawCTLine(rAquaGraphics, pCTLine, mpTextStyle);
313 CFRelease(pCTLine);
314 return true;
316 else
318 return SalLayout::DrawTextSpecial(rGraphics, flags);
322 void CTLayout::drawCTLine(AquaSalGraphics& rAquaGraphics, CTLineRef ctline, const CoreTextStyle* const pStyle) const
324 // the view is vertically flipped => flipped glyphs
325 // so apply a temporary transformation that it flips back
326 // also compensate if the font was size limited
327 CGContextSaveGState( rAquaGraphics.mrContext );
328 CGContextScaleCTM( rAquaGraphics.mrContext, 1.0, -1.0 );
329 CGContextSetShouldAntialias( rAquaGraphics.mrContext, !rAquaGraphics.mbNonAntialiasedText );
331 // Draw the text
332 CGPoint aTextPos = GetTextDrawPosition();
334 if( pStyle->mfFontRotation != 0.0 )
336 const CGFloat fRadians = pStyle->mfFontRotation;
337 CGContextRotateCTM( rAquaGraphics.mrContext, +fRadians );
339 const CGAffineTransform aInvMatrix = CGAffineTransformMakeRotation( -fRadians );
340 aTextPos = CGPointApplyAffineTransform( aTextPos, aInvMatrix );
343 CGContextSetTextPosition( rAquaGraphics.mrContext, aTextPos.x, aTextPos.y );
344 CTLineDraw( ctline, rAquaGraphics.mrContext );
345 #ifndef IOS
346 // request an update of the changed window area
347 if( rAquaGraphics.IsWindowGraphics() )
349 const CGRect aInkRect = CTLineGetImageBounds( mpCTLine, rAquaGraphics.mrContext );
350 const CGRect aRefreshRect = CGContextConvertRectToDeviceSpace( rAquaGraphics.mrContext, aInkRect );
351 rAquaGraphics.RefreshRect( aRefreshRect );
353 #endif
354 // restore the original graphic context transformations
355 CGContextRestoreGState( rAquaGraphics.mrContext );
358 void CTLayout::DrawText( SalGraphics& rGraphics ) const
360 AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics);
362 // short circuit if there is nothing to do
363 if( (mnCharCount <= 0) || !rAquaGraphics.CheckContext() )
364 return;
366 drawCTLine(rAquaGraphics, mpCTLine, mpTextStyle);
369 bool CTLayout::CacheGlyphLayout(void) const // eew!
371 m_vRunData.release();
372 if(!mpCTLine)
374 return false;
376 CFArrayRef aRuns = CTLineGetGlyphRuns( mpCTLine );
377 const int nRun = CFArrayGetCount( aRuns );
378 int nPos = 0;
380 for( int i = 0; i < nRun; ++i )
382 CTRunRef pRun = (CTRunRef)CFArrayGetValueAtIndex( aRuns, i );
383 CTRunData* pRunData = new CTRunData(pRun, nPos);
384 m_vRunData.push_back(pRunData);
385 nPos += pRunData->m_nGlyphs;
387 bLayouted = true;
388 return true;
391 int CTLayout::GetNextGlyphs( int nLen, sal_GlyphId* pOutGlyphIds, Point& rPos, int& nStart,
392 sal_Int32* pGlyphAdvances, int* pCharIndexes,
393 const PhysicalFontFace** pFallbackFonts ) const
395 if( !mpCTLine )
397 return 0;
399 if(!bLayouted)
401 CacheGlyphLayout();
404 if( nStart < 0 ) // first glyph requested?
406 nStart = 0;
408 const PhysicalFontFace* pFallbackFont = NULL;
409 CTFontRef pFont = NULL;
410 CTFontDescriptorRef pFontDesc = NULL;
411 ImplDevFontAttributes rDevFontAttr;
413 boost::ptr_vector<CTRunData>::const_iterator iter = m_vRunData.begin();
415 while(iter != m_vRunData.end() && iter->m_EndPos <= nStart)
417 ++iter;
419 if(iter == m_vRunData.end())
421 return 0;
423 else
425 if( pFallbackFonts )
427 pFont = (CTFontRef)CFDictionaryGetValue( mpTextStyle->GetStyleDict(), kCTFontAttributeName );
428 pFontDesc = CTFontCopyFontDescriptor( iter->m_pFont );
429 rDevFontAttr = DevFontFromCTFontDescriptor( pFontDesc, NULL );
432 int i = nStart;
433 int count = 0;
434 while( i < nStart + nLen )
436 // convert glyph details for VCL
437 int j = i - iter->m_StartPos;
438 *(pOutGlyphIds++) = iter->m_pGlyphs[ j ];
439 if( pGlyphAdvances )
441 *(pGlyphAdvances++) = lrint(iter->m_pAdvances[ j ].width);
443 if( pCharIndexes )
445 *(pCharIndexes++) = iter->m_pStringIndices[ j ] + mnMinCharPos;
447 if( pFallbackFonts )
449 if ( !CFEqual( iter->m_pFont, pFont ) )
451 pFallbackFont = new CoreTextFontData( rDevFontAttr, (sal_IntPtr)pFontDesc );
452 *(pFallbackFonts++) = pFallbackFont;
454 else
456 *(pFallbackFonts++) = NULL;
459 if( i == nStart )
461 const CGPoint& rFirstPos = iter->m_pPositions[ j ];
462 rPos = GetDrawPosition( Point( rFirstPos.x, rFirstPos.y) );
464 i += 1;
465 count += 1;
466 if(i == iter->m_EndPos)
468 // note: we assume that we do not have empty runs in the middle of things
469 ++iter;
470 if( iter == m_vRunData.end())
472 break;
474 if( pFallbackFonts )
476 pFont = (CTFontRef)CFDictionaryGetValue( mpTextStyle->GetStyleDict(), kCTFontAttributeName );
477 pFontDesc = CTFontCopyFontDescriptor( iter->m_pFont );
478 rDevFontAttr = DevFontFromCTFontDescriptor( pFontDesc, NULL );
482 nStart = i;
484 return count;
488 double CTLayout::GetWidth() const
490 if( (mnCharCount <= 0) || !mpCTLine )
491 return 0;
493 if( mfCachedWidth < 0.0 )
495 mfCachedWidth = CTLineGetTypographicBounds( mpCTLine, NULL, NULL, NULL);
498 return mfCachedWidth;
501 long CTLayout::GetTextWidth() const
503 return lrint(GetWidth());
506 long CTLayout::FillDXArray( sal_Int32* pDXArray ) const
508 long nPixWidth = GetTextWidth();
509 // short circuit requests which don't need full details
510 if( !pDXArray )
511 return nPixWidth;
513 // prepare the sub-pixel accurate logical-width array
514 ::std::vector<double> aWidthVector( mnCharCount );
515 if( mnTrailingSpaceCount && (mfTrailingSpaceWidth > 0.0) )
517 const double fOneWidth = mfTrailingSpaceWidth / mnTrailingSpaceCount;
518 ::std::fill_n(aWidthVector.begin() + (mnCharCount - mnTrailingSpaceCount),
519 mnTrailingSpaceCount,
520 fOneWidth);
523 // handle each glyph run
524 CFArrayRef aGlyphRuns = CTLineGetGlyphRuns( mpCTLine );
525 const int nRunCount = CFArrayGetCount( aGlyphRuns );
526 typedef std::vector<CGSize> CGSizeVector;
527 CGSizeVector aSizeVec;
528 typedef std::vector<CFIndex> CFIndexVector;
529 CFIndexVector aIndexVec;
531 for( int nRunIndex = 0; nRunIndex < nRunCount; ++nRunIndex )
533 CTRunRef pGlyphRun = (CTRunRef)CFArrayGetValueAtIndex( aGlyphRuns, nRunIndex );
534 const CFIndex nGlyphCount = CTRunGetGlyphCount( pGlyphRun );
535 const CFRange aFullRange = CFRangeMake( 0, nGlyphCount );
537 aSizeVec.resize( nGlyphCount );
538 aIndexVec.resize( nGlyphCount );
539 CTRunGetAdvances( pGlyphRun, aFullRange, &aSizeVec[0] );
540 CTRunGetStringIndices( pGlyphRun, aFullRange, &aIndexVec[0] );
542 for( int i = 0; i != nGlyphCount; ++i )
544 const int nRelIdx = aIndexVec[i];
545 aWidthVector[nRelIdx] += aSizeVec[i].width;
549 // convert the sub-pixel accurate array into classic pDXArray integers
550 double fWidthSum = 0.0;
551 sal_Int32 nOldDX = 0;
552 for( int i = 0; i < mnCharCount; ++i)
554 const sal_Int32 nNewDX = rint( fWidthSum += aWidthVector[i]);
555 pDXArray[i] = nNewDX - nOldDX;
556 nOldDX = nNewDX;
559 return nPixWidth;
562 sal_Int32 CTLayout::GetTextBreak( long nMaxWidth, long /*nCharExtra*/, int nFactor ) const
564 if( !mpCTLine )
565 return -1;
567 CTTypesetterRef aCTTypeSetter = CTTypesetterCreateWithAttributedString( mpAttrString );
568 const double fCTMaxWidth = (double)nMaxWidth / nFactor;
569 CFIndex nIndex = CTTypesetterSuggestClusterBreak( aCTTypeSetter, 0, fCTMaxWidth );
570 CFRelease( aCTTypeSetter );
572 if( nIndex >= mnCharCount )
573 return -1;
575 nIndex += mnMinCharPos;
576 return nIndex;
579 void CTLayout::GetCaretPositions( int nMaxIndex, sal_Int32* pCaretXArray ) const
581 DBG_ASSERT( ((nMaxIndex>0)&&!(nMaxIndex&1)),
582 "CTLayout::GetCaretPositions() : invalid number of caret pairs requested");
584 // initialize the caret positions
585 for( int i = 0; i < nMaxIndex; ++i )
587 pCaretXArray[ i ] = -1;
589 for( int n = 0; n <= mnCharCount; ++n )
591 // measure the characters cursor position
592 CGFloat fPos2 = -1;
593 const CGFloat fPos1 = CTLineGetOffsetForStringIndex( mpCTLine, n, &fPos2 );
594 (void)fPos2; // TODO: split cursor at line direction change
596 // update previous trailing position
597 if( n > 0 )
598 pCaretXArray[ 2*n-1 ] = lrint( fPos1 );
600 // update current leading position
601 if( 2*n >= nMaxIndex )
602 break;
603 pCaretXArray[ 2*n+0 ] = lrint( fPos1 );
607 bool CTLayout::GetBoundRect( SalGraphics& rGraphics, Rectangle& rVCLRect ) const
609 // Closely mimic DrawText(), except that instead of calling
610 // CTLineDraw() to draw the line, we call CTLineGetImageBounds()
611 // to get its bounds. But all the coordinate system manipulation
612 // before that is the same => should be factored out?
614 AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics);
616 if( !rAquaGraphics.CheckContext() )
617 return false;
619 CGContextSaveGState( rAquaGraphics.mrContext );
620 CGContextScaleCTM( rAquaGraphics.mrContext, 1.0, -1.0 );
621 CGContextSetShouldAntialias( rAquaGraphics.mrContext, !rAquaGraphics.mbNonAntialiasedText );
623 const CGPoint aVclPos = GetTextDrawPosition();
624 CGPoint aTextPos = GetTextDrawPosition();
626 if( mpTextStyle->mfFontRotation != 0.0 )
628 const CGFloat fRadians = mpTextStyle->mfFontRotation;
629 CGContextRotateCTM( rAquaGraphics.mrContext, +fRadians );
631 const CGAffineTransform aInvMatrix = CGAffineTransformMakeRotation( -fRadians );
632 aTextPos = CGPointApplyAffineTransform( aTextPos, aInvMatrix );
635 CGContextSetTextPosition( rAquaGraphics.mrContext, aTextPos.x, aTextPos.y );
636 CGRect aMacRect = CTLineGetImageBounds( mpCTLine, rAquaGraphics.mrContext );
638 if( mpTextStyle->mfFontRotation != 0.0 )
640 const CGFloat fRadians = mpTextStyle->mfFontRotation;
641 const CGAffineTransform aMatrix = CGAffineTransformMakeRotation( +fRadians );
642 aMacRect = CGRectApplyAffineTransform( aMacRect, aMatrix );
645 CGContextRestoreGState( rAquaGraphics.mrContext );
647 rVCLRect.Left() = aVclPos.x + lrint(aMacRect.origin.x);
648 rVCLRect.Right() = aVclPos.x + lrint(aMacRect.origin.x + aMacRect.size.width);
649 rVCLRect.Bottom() = aVclPos.x - lrint(aMacRect.origin.y);
650 rVCLRect.Top() = aVclPos.x - lrint(aMacRect.origin.y + aMacRect.size.height);
652 return true;
655 // glyph fallback is supported directly by Aqua
656 // so methods used only by MultiSalLayout can be dummy implementated
657 void CTLayout::InitFont() const {}
658 void CTLayout::MoveGlyph( int /*nStart*/, long /*nNewXPos*/ ) {}
659 void CTLayout::DropGlyph( int /*nStart*/ ) {}
660 void CTLayout::Simplify( bool /*bIsBase*/ ) {}
662 SalLayout* CoreTextStyle::GetTextLayout( void ) const
664 return new CTLayout( this);
667 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */