atslayout.cxx (51747b8e) atslayout.cxx (e26449d3)
1/**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance

--- 23 unchanged lines hidden (view full) ---

32
33#include <math.h>
34
35// =======================================================================
36
37class ATSLayout : public SalLayout
38{
39public:
1/**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance

--- 23 unchanged lines hidden (view full) ---

32
33#include <math.h>
34
35// =======================================================================
36
37class ATSLayout : public SalLayout
38{
39public:
40 ATSLayout( ATSUStyle&, float fFontScale );
40 explicit ATSLayout( ATSUStyle&, float fFontScale );
41 virtual ~ATSLayout();
42
43 virtual bool LayoutText( ImplLayoutArgs& );
44 virtual void AdjustLayout( ImplLayoutArgs& );
45 virtual void DrawText( SalGraphics& ) const;
46
41 virtual ~ATSLayout();
42
43 virtual bool LayoutText( ImplLayoutArgs& );
44 virtual void AdjustLayout( ImplLayoutArgs& );
45 virtual void DrawText( SalGraphics& ) const;
46
47 virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
47 virtual int GetNextGlyphs( int nLen, sal_GlyphId* pOutGlyphIds, Point& rPos, int&,
48 sal_Int32* pGlyphAdvances, int* pCharIndexes ) const;
49
50 virtual long GetTextWidth() const;
51 virtual long FillDXArray( long* pDXArray ) const;
52 virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
53 virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
54 virtual bool GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const;
55 virtual bool GetBoundRect( SalGraphics&, Rectangle& ) const;

--- 19 unchanged lines hidden (view full) ---

75 bool GetIdealX() const;
76 bool GetDeltaY() const;
77 void InvalidateMeasurements();
78
79 int Fixed2Vcl( Fixed ) const; // convert ATSU-Fixed units to VCL units
80 int AtsuPix2Vcl( int ) const; // convert ATSU-Pixel units to VCL units
81 Fixed Vcl2Fixed( int ) const; // convert VCL units to ATSU-Fixed units
82
48 sal_Int32* pGlyphAdvances, int* pCharIndexes ) const;
49
50 virtual long GetTextWidth() const;
51 virtual long FillDXArray( long* pDXArray ) const;
52 virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
53 virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
54 virtual bool GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const;
55 virtual bool GetBoundRect( SalGraphics&, Rectangle& ) const;

--- 19 unchanged lines hidden (view full) ---

75 bool GetIdealX() const;
76 bool GetDeltaY() const;
77 void InvalidateMeasurements();
78
79 int Fixed2Vcl( Fixed ) const; // convert ATSU-Fixed units to VCL units
80 int AtsuPix2Vcl( int ) const; // convert ATSU-Pixel units to VCL units
81 Fixed Vcl2Fixed( int ) const; // convert VCL units to ATSU-Fixed units
82
83 // cached details about the resulting layout
84 // mutable members since these details are all lazy initialized
85 mutable int mnGlyphCount; // glyph count
86 mutable Fixed mnCachedWidth; // cached value of resulting typographical width
87 int mnTrailingSpaceWidth; // in Pixels
83 // cached details about the resulting layout
84 // mutable members since these details are all lazy initialized
85 mutable int mnGlyphCount; // glyph count
86 mutable Fixed mnCachedWidth; // cached value of resulting typographical width
87 int mnTrailingSpaceWidth; // in Pixels
88
89 mutable ATSGlyphRef* mpGlyphIds; // ATSU glyph ids
88
89 mutable ATSGlyphRef* mpGlyphIds; // ATSU glyph ids
90 mutable Fixed* mpCharWidths; // map relative charpos to charwidth
91 mutable int* mpChars2Glyphs; // map relative charpos to absolute glyphpos
92 mutable int* mpGlyphs2Chars; // map absolute glyphpos to absolute charpos
93 mutable bool* mpGlyphRTLFlags; // BiDi status for glyphs: true if RTL
94 mutable Fixed* mpGlyphAdvances; // contains glyph widths for the justified layout
95 mutable Fixed* mpGlyphOrigAdvs; // contains glyph widths for the unjustified layout
96 mutable Fixed* mpDeltaY; // vertical offset from the baseline
90 mutable Fixed* mpCharWidths; // map relative charpos to charwidth
91 mutable int* mpChars2Glyphs; // map relative charpos to absolute glyphpos
92 mutable int* mpGlyphs2Chars; // map absolute glyphpos to absolute charpos
93 mutable bool* mpGlyphRTLFlags; // BiDi status for glyphs: true if RTL
94 mutable Fixed* mpGlyphAdvances; // contains glyph widths for the justified layout
95 mutable Fixed* mpGlyphOrigAdvs; // contains glyph widths for the unjustified layout
96 mutable Fixed* mpDeltaY; // vertical offset from the baseline
97
98 struct SubPortion { int mnMinCharPos, mnEndCharPos; Fixed mnXOffset; };
99 typedef std::vector<SubPortion> SubPortionVector;
100 mutable SubPortionVector maSubPortions; // Writer&ATSUI layouts can differ quite a bit...
101
97
98 struct SubPortion { int mnMinCharPos, mnEndCharPos; Fixed mnXOffset; };
99 typedef std::vector<SubPortion> SubPortionVector;
100 mutable SubPortionVector maSubPortions; // Writer&ATSUI layouts can differ quite a bit...
101
102 // storing details about fonts used in glyph-fallback for this layout
103 mutable class FallbackInfo* mpFallbackInfo;
102 // storing details about fonts used in glyph-fallback for this layout
103 mutable class FallbackInfo* mpFallbackInfo;
104
104
105 // x-offset relative to layout origin
106 // currently only used in RTL-layouts
107 mutable Fixed mnBaseAdv;
105 // x-offset relative to layout origin
106 // currently only used in RTL-layouts
107 mutable Fixed mnBaseAdv;
108};
109
110class FallbackInfo
111{
112public:
108};
109
110class FallbackInfo
111{
112public:
113 FallbackInfo() : mnMaxLevel(0) {}
114 int AddFallback( ATSUFontID );
115 const ImplFontData* GetFallbackFontData( int nLevel ) const;
113 FallbackInfo() : mnMaxLevel(0) {}
114 int AddFallback( ATSUFontID );
115 const ImplFontData* GetFallbackFontData( int nLevel ) const;
116
117private:
116
117private:
118 const ImplMacFontData* maFontData[ MAX_FALLBACK ];
119 ATSUFontID maATSUFontId[ MAX_FALLBACK ];
120 int mnMaxLevel;
118 const ImplMacFontData* maFontData[ MAX_FALLBACK ];
119 ATSUFontID maATSUFontId[ MAX_FALLBACK ];
120 int mnMaxLevel;
121};
122
123// =======================================================================
124
125ATSLayout::ATSLayout( ATSUStyle& rATSUStyle, float fFontScale )
121};
122
123// =======================================================================
124
125ATSLayout::ATSLayout( ATSUStyle& rATSUStyle, float fFontScale )
126: mrATSUStyle( rATSUStyle ),
126: mrATSUStyle( rATSUStyle ),
127 maATSULayout( NULL ),
128 mnCharCount( 0 ),
129 mfFontScale( fFontScale ),
130 mnGlyphCount( -1 ),
131 mnCachedWidth( 0 ),
132 mnTrailingSpaceWidth( 0 ),
133 mpGlyphIds( NULL ),
134 mpCharWidths( NULL ),

--- 6 unchanged lines hidden (view full) ---

141 mpFallbackInfo( NULL ),
142 mnBaseAdv( 0 )
143{}
144
145// -----------------------------------------------------------------------
146
147ATSLayout::~ATSLayout()
148{
127 maATSULayout( NULL ),
128 mnCharCount( 0 ),
129 mfFontScale( fFontScale ),
130 mnGlyphCount( -1 ),
131 mnCachedWidth( 0 ),
132 mnTrailingSpaceWidth( 0 ),
133 mpGlyphIds( NULL ),
134 mpCharWidths( NULL ),

--- 6 unchanged lines hidden (view full) ---

141 mpFallbackInfo( NULL ),
142 mnBaseAdv( 0 )
143{}
144
145// -----------------------------------------------------------------------
146
147ATSLayout::~ATSLayout()
148{
149 if( mpDeltaY )
150 ATSUDirectReleaseLayoutDataArrayPtr( NULL,
151 kATSUDirectDataBaselineDeltaFixedArray, (void**)&mpDeltaY );
149 if( mpDeltaY )
150 ATSUDirectReleaseLayoutDataArrayPtr( NULL,
151 kATSUDirectDataBaselineDeltaFixedArray, (void**)&mpDeltaY );
152
152
153 if( maATSULayout )
154 ATSUDisposeTextLayout( maATSULayout );
153 if( maATSULayout )
154 ATSUDisposeTextLayout( maATSULayout );
155
155
156 delete[] mpGlyphRTLFlags;
157 delete[] mpGlyphs2Chars;
158 delete[] mpChars2Glyphs;
159 if( mpCharWidths != mpGlyphAdvances )
160 delete[] mpCharWidths;
161 delete[] mpGlyphIds;
162 delete[] mpGlyphOrigAdvs;
163 delete[] mpGlyphAdvances;
156 delete[] mpGlyphRTLFlags;
157 delete[] mpGlyphs2Chars;
158 delete[] mpChars2Glyphs;
159 if( mpCharWidths != mpGlyphAdvances )
160 delete[] mpCharWidths;
161 delete[] mpGlyphIds;
162 delete[] mpGlyphOrigAdvs;
163 delete[] mpGlyphAdvances;
164
164
165 delete mpFallbackInfo;
165 delete mpFallbackInfo;
166}
167
168// -----------------------------------------------------------------------
169
170inline int ATSLayout::Fixed2Vcl( Fixed nFixed ) const
171{
172 float fFloat = mfFontScale * FixedToFloat( nFixed );
173 return static_cast<int>(fFloat + 0.5);

--- 26 unchanged lines hidden (view full) ---

200 *
201 * @return : true if everything is ok
202**/
203bool ATSLayout::LayoutText( ImplLayoutArgs& rArgs )
204{
205 if( maATSULayout )
206 ATSUDisposeTextLayout( maATSULayout );
207
166}
167
168// -----------------------------------------------------------------------
169
170inline int ATSLayout::Fixed2Vcl( Fixed nFixed ) const
171{
172 float fFloat = mfFontScale * FixedToFloat( nFixed );
173 return static_cast<int>(fFloat + 0.5);

--- 26 unchanged lines hidden (view full) ---

200 *
201 * @return : true if everything is ok
202**/
203bool ATSLayout::LayoutText( ImplLayoutArgs& rArgs )
204{
205 if( maATSULayout )
206 ATSUDisposeTextLayout( maATSULayout );
207
208 maATSULayout = NULL;
208 maATSULayout = NULL;
209
210 // Layout text
211 // set up our locals, verify parameters...
209
210 // Layout text
211 // set up our locals, verify parameters...
212 DBG_ASSERT( (rArgs.mpStr!=NULL), "ATSLayout::LayoutText() with rArgs.mpStr==NULL !!!");
213 DBG_ASSERT( (mrATSUStyle!=NULL), "ATSLayout::LayoutText() with ATSUStyle==NULL !!!");
212 DBG_ASSERT( (rArgs.mpStr!=NULL), "ATSLayout::LayoutText() with rArgs.mpStr==NULL !!!");
213 DBG_ASSERT( (mrATSUStyle!=NULL), "ATSLayout::LayoutText() with ATSUStyle==NULL !!!");
214
215 SalLayout::AdjustLayout( rArgs );
216 mnCharCount = mnEndCharPos - mnMinCharPos;
217
218 // Workaround a bug in ATSUI with empty string
219 if( mnCharCount<=0 )
220 return false;
221
214
215 SalLayout::AdjustLayout( rArgs );
216 mnCharCount = mnEndCharPos - mnMinCharPos;
217
218 // Workaround a bug in ATSUI with empty string
219 if( mnCharCount<=0 )
220 return false;
221
222#if (OSL_DEBUG_LEVEL > 3)
223 Fixed fFontSize = 0;
224 ByteCount nDummy;
225 ATSUGetAttribute( mrATSUStyle, kATSUSizeTag, sizeof(fFontSize), &fFontSize, &nDummy);
226 String aUniName( &rArgs.mpStr[rArgs.mnMinCharPos], mnCharCount );
227 ByteString aCName( aUniName, RTL_TEXTENCODING_UTF8 );
228 fprintf( stderr, "ATSLayout( \"%s\" %d..%d of %d) with h=%4.1f\n",
229 aCName.GetBuffer(),rArgs.mnMinCharPos,rArgs.mnEndCharPos,rArgs.mnLength,Fix2X(fFontSize) );
230#endif
231
232 // create the ATSUI layout
233 UniCharCount nRunLengths[1] = { mnCharCount };
234 const int nRunCount = sizeof(nRunLengths)/sizeof(*nRunLengths);
235 OSStatus eStatus = ATSUCreateTextLayoutWithTextPtr( rArgs.mpStr,
222 // create the ATSUI layout
223 UniCharCount nRunLengths[1] = { mnCharCount };
224 const int nRunCount = sizeof(nRunLengths)/sizeof(*nRunLengths);
225 OSStatus eStatus = ATSUCreateTextLayoutWithTextPtr( rArgs.mpStr,
236 rArgs.mnMinCharPos, mnCharCount, rArgs.mnLength,
237 nRunCount, &nRunLengths[0], &mrATSUStyle,
238 &maATSULayout);
226 rArgs.mnMinCharPos, mnCharCount, rArgs.mnLength,
227 nRunCount, &nRunLengths[0], &mrATSUStyle, &maATSULayout);
239
240 DBG_ASSERT( (eStatus==noErr), "ATSUCreateTextLayoutWithTextPtr failed\n");
241 if( eStatus != noErr )
242 return false;
243
244 // prepare setting of layout controls
245 static const int nMaxTagCount = 1;
246 ATSUAttributeTag aTagAttrs[ nMaxTagCount ];

--- 19 unchanged lines hidden (view full) ---

266 // control BiDi defaults
267 BOOL nLineDirTag = kATSULeftToRightBaseDirection;
268 if( (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) != 0 )
269 nLineDirTag = kATSURightToLeftBaseDirection;
270 aTagAttrs[0] = kATSULineDirectionTag;
271 aTagSizes[0] = sizeof( nLineDirTag );
272 aTagValues[0] = &nLineDirTag;
273 // set run-specific layout controls
228
229 DBG_ASSERT( (eStatus==noErr), "ATSUCreateTextLayoutWithTextPtr failed\n");
230 if( eStatus != noErr )
231 return false;
232
233 // prepare setting of layout controls
234 static const int nMaxTagCount = 1;
235 ATSUAttributeTag aTagAttrs[ nMaxTagCount ];

--- 19 unchanged lines hidden (view full) ---

255 // control BiDi defaults
256 BOOL nLineDirTag = kATSULeftToRightBaseDirection;
257 if( (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) != 0 )
258 nLineDirTag = kATSURightToLeftBaseDirection;
259 aTagAttrs[0] = kATSULineDirectionTag;
260 aTagSizes[0] = sizeof( nLineDirTag );
261 aTagValues[0] = &nLineDirTag;
262 // set run-specific layout controls
274#if 0 // why don't line-controls work as reliably as layout-controls???
263#if 0 // why don't line-controls work as reliable as layout-controls???
275 ATSUSetLineControls( maATSULayout, rArgs.mnMinCharPos, 1, aTagAttrs, aTagSizes, aTagValues );
276#else
277 ATSUSetLayoutControls( maATSULayout, 1, aTagAttrs, aTagSizes, aTagValues );
278#endif
279 }
280
281 return true;
282}

--- 21 unchanged lines hidden (view full) ---

304 int i = mnCharCount;
305 while( (--i >= 0) && IsSpacingGlyph( rArgs.mpStr[mnMinCharPos+i]|GF_ISCHAR ) ) {}
306 if( i < 0 ) // nothing to do if the text is all spaces
307 return;
308 // #i91685# trailing letters are left aligned (right aligned for RTL)
309 mnTrailingSpaceWidth = rArgs.mpDXArray[ mnCharCount-1 ];
310 if( i > 0 )
311 mnTrailingSpaceWidth -= rArgs.mpDXArray[ i-1 ];
264 ATSUSetLineControls( maATSULayout, rArgs.mnMinCharPos, 1, aTagAttrs, aTagSizes, aTagValues );
265#else
266 ATSUSetLayoutControls( maATSULayout, 1, aTagAttrs, aTagSizes, aTagValues );
267#endif
268 }
269
270 return true;
271}

--- 21 unchanged lines hidden (view full) ---

293 int i = mnCharCount;
294 while( (--i >= 0) && IsSpacingGlyph( rArgs.mpStr[mnMinCharPos+i]|GF_ISCHAR ) ) {}
295 if( i < 0 ) // nothing to do if the text is all spaces
296 return;
297 // #i91685# trailing letters are left aligned (right aligned for RTL)
298 mnTrailingSpaceWidth = rArgs.mpDXArray[ mnCharCount-1 ];
299 if( i > 0 )
300 mnTrailingSpaceWidth -= rArgs.mpDXArray[ i-1 ];
312 InitGIA(); // ensure valid mpCharWidths[], TODO: use GetIdealX() instead?
301 InitGIA(); // ensure valid mpCharWidths[], TODO: use GetIdealX() instead?
313 mnTrailingSpaceWidth -= Fixed2Vcl( mpCharWidths[i] );
314 // ignore trailing space for calculating the available width
315 nOrigWidth -= mnTrailingSpaceWidth;
316 nPixelWidth -= mnTrailingSpaceWidth;
317 // in RTL-layouts trailing spaces are leftmost
318 // TODO: use BiDi-algorithm to thoroughly check this assumption
319 if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL)
320 mnBaseAdv = mnTrailingSpaceWidth;

--- 54 unchanged lines hidden (view full) ---

375 AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics);
376
377 // short circuit if there is nothing to do
378 if( (mnCharCount <= 0)
379 || !rAquaGraphics.CheckContext() )
380 return;
381
382 // the view is vertically flipped => flipped glyphs
302 mnTrailingSpaceWidth -= Fixed2Vcl( mpCharWidths[i] );
303 // ignore trailing space for calculating the available width
304 nOrigWidth -= mnTrailingSpaceWidth;
305 nPixelWidth -= mnTrailingSpaceWidth;
306 // in RTL-layouts trailing spaces are leftmost
307 // TODO: use BiDi-algorithm to thoroughly check this assumption
308 if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL)
309 mnBaseAdv = mnTrailingSpaceWidth;

--- 54 unchanged lines hidden (view full) ---

364 AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics);
365
366 // short circuit if there is nothing to do
367 if( (mnCharCount <= 0)
368 || !rAquaGraphics.CheckContext() )
369 return;
370
371 // the view is vertically flipped => flipped glyphs
383 // so apply a temporary transformation that it flips back
372 // so apply a temporary transformation that it flips back
384 // also compensate if the font was size limited
373 // also compensate if the font was size limited
385 CGContextSaveGState( rAquaGraphics.mrContext );
386 CGContextScaleCTM( rAquaGraphics.mrContext, +mfFontScale, -mfFontScale );
387 CGContextSetShouldAntialias( rAquaGraphics.mrContext, !rAquaGraphics.mbNonAntialiasedText );
374 CGContextSaveGState( rAquaGraphics.mrContext );
375 CGContextScaleCTM( rAquaGraphics.mrContext, +mfFontScale, -mfFontScale );
376 CGContextSetShouldAntialias( rAquaGraphics.mrContext, !rAquaGraphics.mbNonAntialiasedText );
388
389 // prepare ATSUI drawing attributes
390 static const ItemCount nMaxControls = 8;
391 ATSUAttributeTag theTags[ nMaxControls ];
392 ByteCount theSizes[ nMaxControls];
393 ATSUAttributeValuePtr theValues[ nMaxControls ];
394 ItemCount numcontrols = 0;
395
396 // Tell ATSUI to use CoreGraphics
377
378 // prepare ATSUI drawing attributes
379 static const ItemCount nMaxControls = 8;
380 ATSUAttributeTag theTags[ nMaxControls ];
381 ByteCount theSizes[ nMaxControls];
382 ATSUAttributeValuePtr theValues[ nMaxControls ];
383 ItemCount numcontrols = 0;
384
385 // Tell ATSUI to use CoreGraphics
397 theTags[numcontrols] = kATSUCGContextTag;
398 theSizes[numcontrols] = sizeof( CGContextRef );
399 theValues[numcontrols++] = &rAquaGraphics.mrContext;
386 theTags[numcontrols] = kATSUCGContextTag;
387 theSizes[numcontrols] = sizeof( CGContextRef );
388 theValues[numcontrols++] = &rAquaGraphics.mrContext;
400
401 // Rotate if necessary
402 if( rAquaGraphics.mnATSUIRotation != 0 )
403 {
404 Fixed theAngle = rAquaGraphics.mnATSUIRotation;
405 theTags[numcontrols] = kATSULineRotationTag;
406 theSizes[numcontrols] = sizeof( Fixed );
407 theValues[numcontrols++] = &theAngle;

--- 34 unchanged lines hidden (view full) ---

442
443 // request an update of the changed window area
444 if( rAquaGraphics.IsWindowGraphics() )
445 {
446 Rect drawRect; // rectangle of the changed area
447 theErr = ATSUMeasureTextImage( maATSULayout,
448 mnMinCharPos, mnCharCount, nFixedX, nFixedY, &drawRect );
449 if( theErr == noErr )
389
390 // Rotate if necessary
391 if( rAquaGraphics.mnATSUIRotation != 0 )
392 {
393 Fixed theAngle = rAquaGraphics.mnATSUIRotation;
394 theTags[numcontrols] = kATSULineRotationTag;
395 theSizes[numcontrols] = sizeof( Fixed );
396 theValues[numcontrols++] = &theAngle;

--- 34 unchanged lines hidden (view full) ---

431
432 // request an update of the changed window area
433 if( rAquaGraphics.IsWindowGraphics() )
434 {
435 Rect drawRect; // rectangle of the changed area
436 theErr = ATSUMeasureTextImage( maATSULayout,
437 mnMinCharPos, mnCharCount, nFixedX, nFixedY, &drawRect );
438 if( theErr == noErr )
450 {
451 // FIXME: transformation from baseline to top left
452 // with the simple approach below we invalidate too much
453 short d = drawRect.bottom - drawRect.top;
454 drawRect.top -= d;
455 drawRect.bottom += d;
456 CGRect aRect = CGRectMake( drawRect.left, drawRect.top,
457 drawRect.right - drawRect.left,
458 drawRect.bottom - drawRect.top );
459 aRect = CGContextConvertRectToDeviceSpace( rAquaGraphics.mrContext, aRect );
439 {
440 // FIXME: transformation from baseline to top left
441 // with the simple approach below we invalidate too much
442 short d = drawRect.bottom - drawRect.top;
443 drawRect.top -= d;
444 drawRect.bottom += d;
445 CGRect aRect = CGRectMake( drawRect.left, drawRect.top,
446 drawRect.right - drawRect.left,
447 drawRect.bottom - drawRect.top );
448 aRect = CGContextConvertRectToDeviceSpace( rAquaGraphics.mrContext, aRect );
460 rAquaGraphics.RefreshRect( aRect );
449 rAquaGraphics.RefreshRect( aRect );
461 }
450 }
462 }
463
451 }
452
464 // restore the original graphic context transformations
453 // restore the original graphic context transformations
465 CGContextRestoreGState( rAquaGraphics.mrContext );
466}
467
468// -----------------------------------------------------------------------
469/**
470 * ATSLayout::GetNextGlyphs : Get info about next glyphs in the layout
471 *
472 * @param nLen: max number of char
473 * @param pGlyphs: returned array of glyph ids
474 * @param rPos: returned x starting position
475 * @param nStart: index of the first requested glyph
476 * @param pGlyphAdvances: returned array of glyphs advances
477 * @param pCharIndexes: returned array of char indexes
478 *
479 * Returns infos about the next glyphs in the text layout
480 *
481 * @return : number of glyph details that were provided
482**/
483int ATSLayout::GetNextGlyphs( int nLen, sal_GlyphId* pOutGlyphIds, Point& rPos, int& nStart,
454 CGContextRestoreGState( rAquaGraphics.mrContext );
455}
456
457// -----------------------------------------------------------------------
458/**
459 * ATSLayout::GetNextGlyphs : Get info about next glyphs in the layout
460 *
461 * @param nLen: max number of char
462 * @param pGlyphs: returned array of glyph ids
463 * @param rPos: returned x starting position
464 * @param nStart: index of the first requested glyph
465 * @param pGlyphAdvances: returned array of glyphs advances
466 * @param pCharIndexes: returned array of char indexes
467 *
468 * Returns infos about the next glyphs in the text layout
469 *
470 * @return : number of glyph details that were provided
471**/
472int ATSLayout::GetNextGlyphs( int nLen, sal_GlyphId* pOutGlyphIds, Point& rPos, int& nStart,
484 sal_Int32* pGlyphAdvances, int* pCharIndexes ) const
473 sal_Int32* pGlyphAdvances, int* pCharIndexes ) const
485{
486 if( nStart < 0 ) // first glyph requested?
487 nStart = 0;
488
489 // get glyph measurements
490 InitGIA();
491 // some measurements are only needed for multi-glyph results
492 if( nLen > 1 )
493 {
494 GetIdealX();
495 GetDeltaY();
496 }
497
498 if( nStart >= mnGlyphCount ) // no glyph left?
499 return 0;
500
501 // calculate glyph position relative to layout base
474{
475 if( nStart < 0 ) // first glyph requested?
476 nStart = 0;
477
478 // get glyph measurements
479 InitGIA();
480 // some measurements are only needed for multi-glyph results
481 if( nLen > 1 )
482 {
483 GetIdealX();
484 GetDeltaY();
485 }
486
487 if( nStart >= mnGlyphCount ) // no glyph left?
488 return 0;
489
490 // calculate glyph position relative to layout base
502 // TODO: avoid for nStart!=0 case by reusing rPos
503 Fixed nXOffset = mnBaseAdv;
504 for( int i = 0; i < nStart; ++i )
505 nXOffset += mpGlyphAdvances[ i ];
506 // if sub-portion offsets are involved there is an additional x-offset
507 if( !maSubPortions.empty() )
508 {
509 // prepare to find the sub-portion
510 int nCharPos = nStart + mnMinCharPos;
511 if( mpGlyphs2Chars )
512 nCharPos = mpGlyphs2Chars[nStart];
491 // TODO: avoid for nStart!=0 case by reusing rPos
492 Fixed nXOffset = mnBaseAdv;
493 for( int i = 0; i < nStart; ++i )
494 nXOffset += mpGlyphAdvances[ i ];
495 // if sub-portion offsets are involved there is an additional x-offset
496 if( !maSubPortions.empty() )
497 {
498 // prepare to find the sub-portion
499 int nCharPos = nStart + mnMinCharPos;
500 if( mpGlyphs2Chars )
501 nCharPos = mpGlyphs2Chars[nStart];
513
502
514 // find the matching subportion
515 // TODO: is a non-linear search worth it?
516 SubPortionVector::const_iterator it = maSubPortions.begin();
517 for(; it != maSubPortions.end(); ++it) {
518 const SubPortion& r = *it;
519 if( nCharPos < r.mnMinCharPos )
520 continue;
521 if( nCharPos >= r.mnEndCharPos )
522 continue;
523 // apply the sub-portion xoffset
524 nXOffset += r.mnXOffset;
525 break;
526 }
527 }
503 // find the matching subportion
504 // TODO: is a non-linear search worth it?
505 SubPortionVector::const_iterator it = maSubPortions.begin();
506 for(; it != maSubPortions.end(); ++it) {
507 const SubPortion& r = *it;
508 if( nCharPos < r.mnMinCharPos )
509 continue;
510 if( nCharPos >= r.mnEndCharPos )
511 continue;
512 // apply the sub-portion xoffset
513 nXOffset += r.mnXOffset;
514 break;
515 }
516 }
528
529 Fixed nYOffset = 0;
530 if( mpDeltaY )
531 nYOffset = mpDeltaY[ nStart ];
532
517
518 Fixed nYOffset = 0;
519 if( mpDeltaY )
520 nYOffset = mpDeltaY[ nStart ];
521
533 // calculate absolute position in pixel units
534 const Point aRelativePos( Fix2Long(static_cast<Fixed>(nXOffset*mfFontScale)), Fix2Long(static_cast<Fixed>(nYOffset*mfFontScale)) );
535 rPos = GetDrawPosition( aRelativePos );
522 // calculate absolute position in pixel units
523 const Point aRelativePos( Fix2Long(static_cast<Fixed>(nXOffset*mfFontScale)), Fix2Long(static_cast<Fixed>(nYOffset*mfFontScale)) );
524 rPos = GetDrawPosition( aRelativePos );
536
537 // update return values
538 int nCount = 0;
525
526 // update return values
527 int nCount = 0;
539 while( nCount < nLen )
540 {
541 ++nCount;
542 sal_GlyphId aGlyphId = mpGlyphIds[ nStart];
528 while( nCount < nLen )
529 {
530 ++nCount;
531 sal_GlyphId aGlyphId = mpGlyphIds[nStart];
543
532
544 // check if glyph fallback is needed for this glyph
545 // TODO: use ATSUDirectGetLayoutDataArrayPtrFromTextLayout(kATSUDirectDataStyleIndex) API instead?
546 const int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[nStart] : nStart + mnMinCharPos;
547 ATSUFontID nFallbackFontID = kATSUInvalidFontID;
548 UniCharArrayOffset nChangedOffset = 0;
549 UniCharCount nChangedLength = 0;
550 OSStatus eStatus = ATSUMatchFontsToText( maATSULayout, nCharPos, kATSUToTextEnd,
551 &nFallbackFontID, &nChangedOffset, &nChangedLength );
552 if( (eStatus == kATSUFontsMatched) && ((int)nChangedOffset == nCharPos) )
553 {
554 // fallback is needed
555 if( !mpFallbackInfo )
556 mpFallbackInfo = new FallbackInfo;
557 // register fallback font
558 const int nLevel = mpFallbackInfo->AddFallback( nFallbackFontID );
559 // update sal_GlyphId with fallback level
560 aGlyphId |= (nLevel << GF_FONTSHIFT);
561 }
533 // check if glyph fallback is needed for this glyph
534 // TODO: use ATSUDirectGetLayoutDataArrayPtrFromTextLayout(kATSUDirectDataStyleIndex) API instead?
535 const int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[nStart] : nStart + mnMinCharPos;
536 ATSUFontID nFallbackFontID = kATSUInvalidFontID;
537 UniCharArrayOffset nChangedOffset = 0;
538 UniCharCount nChangedLength = 0;
539 OSStatus eStatus = ATSUMatchFontsToText( maATSULayout, nCharPos, kATSUToTextEnd,
540 &nFallbackFontID, &nChangedOffset, &nChangedLength );
541 if( (eStatus == kATSUFontsMatched) && ((int)nChangedOffset == nCharPos) )
542 {
543 // fallback is needed
544 if( !mpFallbackInfo )
545 mpFallbackInfo = new FallbackInfo;
546 // register fallback font
547 const int nLevel = mpFallbackInfo->AddFallback( nFallbackFontID );
548 // update sal_GlyphId with fallback level
549 aGlyphId |= (nLevel << GF_FONTSHIFT);
550 }
562
551
563 // update resulting glyphid array
564 *(pOutGlyphIds++) = aGlyphId;
552 // update resulting glyphid array
553 *(pOutGlyphIds++) = aGlyphId;
565
554
566 // update returned glyph advance array
567 if( pGlyphAdvances )
568 *(pGlyphAdvances++) = Fixed2Vcl( mpGlyphAdvances[nStart] );
555 // update returned glyph advance array
556 if( pGlyphAdvances )
557 *(pGlyphAdvances++) = Fixed2Vcl( mpGlyphAdvances[nStart] );
569
558
570 // update returned index-into-string array
571 if( pCharIndexes )
572 {
573 int nCharPos;
574 if( mpGlyphs2Chars )
575 nCharPos = mpGlyphs2Chars[nStart];
576 else
577 nCharPos = nStart + mnMinCharPos;
578 *(pCharIndexes++) = nCharPos;
579 }
580
581 // stop at last glyph
582 if( ++nStart >= mnGlyphCount )
583 break;
559 // update returned index-into-string array
560 if( pCharIndexes )
561 {
562 int nCharPos;
563 if( mpGlyphs2Chars )
564 nCharPos = mpGlyphs2Chars[nStart];
565 else
566 nCharPos = nStart + mnMinCharPos;
567 *(pCharIndexes++) = nCharPos;
568 }
569
570 // stop at last glyph
571 if( ++nStart >= mnGlyphCount )
572 break;
584
573
585 // stop when next the x-position is unexpected
586 if( !maSubPortions.empty() )
587 break; // TODO: finish the complete sub-portion
588 if( !pGlyphAdvances && mpGlyphOrigAdvs )
589 if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] )
590 break;
574 // stop when next the x-position is unexpected
575 if( !maSubPortions.empty() )
576 break; // TODO: finish the complete sub-portion
577 if( !pGlyphAdvances && mpGlyphOrigAdvs )
578 if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] )
579 break;
591
580
592 // stop when the next y-position is unexpected
593 if( mpDeltaY )
594 if( mpDeltaY[nStart-1] != mpDeltaY[nStart] )
595 break;
596 }
581 // stop when the next y-position is unexpected
582 if( mpDeltaY )
583 if( mpDeltaY[nStart-1] != mpDeltaY[nStart] )
584 break;
585 }
597
586
598 return nCount;
587 return nCount;
599}
600
601// -----------------------------------------------------------------------
602/**
603 * ATSLayout::GetTextWidth : Get typographic width of layouted text
604 *
605 * Get typographic bounds of the text
606 *

--- 44 unchanged lines hidden (view full) ---

651 nRightBound = rTrap.lowerRight.x;
652 }
653
654 // measure the bound extremas
655 mnCachedWidth = nRightBound - nLeftBound;
656 // adjust for eliminated trailing space widths
657 }
658
588}
589
590// -----------------------------------------------------------------------
591/**
592 * ATSLayout::GetTextWidth : Get typographic width of layouted text
593 *
594 * Get typographic bounds of the text
595 *

--- 44 unchanged lines hidden (view full) ---

640 nRightBound = rTrap.lowerRight.x;
641 }
642
643 // measure the bound extremas
644 mnCachedWidth = nRightBound - nLeftBound;
645 // adjust for eliminated trailing space widths
646 }
647
659 int nScaledWidth = Fixed2Vcl( mnCachedWidth );
648 int nScaledWidth = Fixed2Vcl( mnCachedWidth );
660 nScaledWidth += mnTrailingSpaceWidth;
649 nScaledWidth += mnTrailingSpaceWidth;
661 return nScaledWidth;
650 return nScaledWidth;
662}
663
664// -----------------------------------------------------------------------
665/**
666 * ATSLayout::FillDXArray : Get Char widths
667 *
668 * @param pDXArray: array to be filled with x-advances
669 *
670 * Fill the pDXArray with horizontal deltas : CharWidths
671 *
672 * @return : typographical width of the complete text layout
673**/
674long ATSLayout::FillDXArray( long* pDXArray ) const
675{
651}
652
653// -----------------------------------------------------------------------
654/**
655 * ATSLayout::FillDXArray : Get Char widths
656 *
657 * @param pDXArray: array to be filled with x-advances
658 *
659 * Fill the pDXArray with horizontal deltas : CharWidths
660 *
661 * @return : typographical width of the complete text layout
662**/
663long ATSLayout::FillDXArray( long* pDXArray ) const
664{
676 // short circuit requests which don't need full details
677 if( !pDXArray )
678 return GetTextWidth();
665 // short circuit requests which don't need full details
666 if( !pDXArray )
667 return GetTextWidth();
679
680 // check assumptions
681 DBG_ASSERT( !mnTrailingSpaceWidth, "ATSLayout::FillDXArray() with nTSW!=0" );
682
683 // initialize details about the resulting layout
668
669 // check assumptions
670 DBG_ASSERT( !mnTrailingSpaceWidth, "ATSLayout::FillDXArray() with nTSW!=0" );
671
672 // initialize details about the resulting layout
684 InitGIA();
673 InitGIA();
685
674
686 // distribute the widths among the string elements
687 int nPixWidth = 0;
688 mnCachedWidth = 0;
689 for( int i = 0; i < mnCharCount; ++i )
690 {
691 // convert and adjust for accumulated rounding errors
692 mnCachedWidth += mpCharWidths[i];
693 const int nOldPixWidth = nPixWidth;
694 nPixWidth = Fixed2Vcl( mnCachedWidth );
695 pDXArray[i] = nPixWidth - nOldPixWidth;
696 }
675 // distribute the widths among the string elements
676 int nPixWidth = 0;
677 mnCachedWidth = 0;
678 for( int i = 0; i < mnCharCount; ++i )
679 {
680 // convert and adjust for accumulated rounding errors
681 mnCachedWidth += mpCharWidths[i];
682 const int nOldPixWidth = nPixWidth;
683 nPixWidth = Fixed2Vcl( mnCachedWidth );
684 pDXArray[i] = nPixWidth - nOldPixWidth;
685 }
697
686
698 return nPixWidth;
687 return nPixWidth;
699}
700
701// -----------------------------------------------------------------------
702/**
703 * ATSLayout::GetTextBreak : Find line break depending on width
704 *
705 * @param nMaxWidth : maximal logical text width in subpixel units
706 * @param nCharExtra: expanded/condensed spacing in subpixel units

--- 30 unchanged lines hidden (view full) ---

737 if( i+1 < mnCharCount )
738 return (mnMinCharPos + i);
739 }
740
741 return STRING_LEN;
742 }
743
744 // get a quick overview on what could fit
688}
689
690// -----------------------------------------------------------------------
691/**
692 * ATSLayout::GetTextBreak : Find line break depending on width
693 *
694 * @param nMaxWidth : maximal logical text width in subpixel units
695 * @param nCharExtra: expanded/condensed spacing in subpixel units

--- 30 unchanged lines hidden (view full) ---

726 if( i+1 < mnCharCount )
727 return (mnMinCharPos + i);
728 }
729
730 return STRING_LEN;
731 }
732
733 // get a quick overview on what could fit
745 const long nPixelWidth = (nMaxWidth - (nCharExtra * mnCharCount)) / nFactor;
746 if( nPixelWidth <= 0 )
747 return mnMinCharPos;
734 const long nPixelWidth = (nMaxWidth - (nCharExtra * mnCharCount)) / nFactor;
735 if( nPixelWidth <= 0 )
736 return mnMinCharPos;
748
749 // check assumptions
750 DBG_ASSERT( !mnTrailingSpaceWidth, "ATSLayout::GetTextBreak() with nTSW!=0" );
751
752 // initial measurement of text break position
753 UniCharArrayOffset nBreakPos = mnMinCharPos;
754 const ATSUTextMeasurement nATSUMaxWidth = Vcl2Fixed( nPixelWidth );
755 if( nATSUMaxWidth <= 0xFFFF ) // #i108584# avoid ATSU rejecting the parameter

--- 42 unchanged lines hidden (view full) ---

798 * @return : none
799**/
800void ATSLayout::GetCaretPositions( int nMaxIndex, long* pCaretXArray ) const
801{
802 DBG_ASSERT( ((nMaxIndex>0)&&!(nMaxIndex&1)),
803 "ATSLayout::GetCaretPositions() : invalid number of caret pairs requested");
804
805 // initialize the caret positions
737
738 // check assumptions
739 DBG_ASSERT( !mnTrailingSpaceWidth, "ATSLayout::GetTextBreak() with nTSW!=0" );
740
741 // initial measurement of text break position
742 UniCharArrayOffset nBreakPos = mnMinCharPos;
743 const ATSUTextMeasurement nATSUMaxWidth = Vcl2Fixed( nPixelWidth );
744 if( nATSUMaxWidth <= 0xFFFF ) // #i108584# avoid ATSU rejecting the parameter

--- 42 unchanged lines hidden (view full) ---

787 * @return : none
788**/
789void ATSLayout::GetCaretPositions( int nMaxIndex, long* pCaretXArray ) const
790{
791 DBG_ASSERT( ((nMaxIndex>0)&&!(nMaxIndex&1)),
792 "ATSLayout::GetCaretPositions() : invalid number of caret pairs requested");
793
794 // initialize the caret positions
806 for( int i = 0; i < nMaxIndex; ++i )
807 pCaretXArray[ i ] = -1;
795 for( int i = 0; i < nMaxIndex; ++i )
796 pCaretXArray[ i ] = -1;
808
809 for( int n = 0; n <= mnCharCount; ++n )
810 {
811 // measure the characters cursor position
812 typedef unsigned char Boolean;
813 const Boolean bIsLeading = true;
814 ATSUCaret aCaret0, aCaret1;
815 Boolean bIsSplit;

--- 222 unchanged lines hidden (view full) ---

1038
1039bool ATSLayout::GetDeltaY() const
1040{
1041 // don't bother to get the same delta-y-array more than once
1042 if( mpDeltaY != NULL )
1043 return true;
1044
1045#if 1
797
798 for( int n = 0; n <= mnCharCount; ++n )
799 {
800 // measure the characters cursor position
801 typedef unsigned char Boolean;
802 const Boolean bIsLeading = true;
803 ATSUCaret aCaret0, aCaret1;
804 Boolean bIsSplit;

--- 222 unchanged lines hidden (view full) ---

1027
1028bool ATSLayout::GetDeltaY() const
1029{
1030 // don't bother to get the same delta-y-array more than once
1031 if( mpDeltaY != NULL )
1032 return true;
1033
1034#if 1
1046 if( !maATSULayout )
1035 if( !maATSULayout )
1047 return false;
1048
1049 // get and keep the y-deltas in the mpDeltaY member variable
1050 // => release it in the destructor
1051 ItemCount nDeltaCount = 0;
1052 OSStatus theErr = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(
1053 maATSULayout, mnMinCharPos, kATSUDirectDataBaselineDeltaFixedArray,
1054 (void**)&mpDeltaY, &nDeltaCount );

--- 151 unchanged lines hidden (view full) ---

1206void ATSLayout::MoveGlyph( int /*nStart*/, long /*nNewXPos*/ ) {}
1207void ATSLayout::DropGlyph( int /*nStart*/ ) {}
1208void ATSLayout::Simplify( bool /*bIsBase*/ ) {}
1209
1210// get the ImplFontData for a glyph fallback font
1211// for a glyphid that was returned by ATSLayout::GetNextGlyphs()
1212const ImplFontData* ATSLayout::GetFallbackFontData( sal_GlyphId aGlyphId ) const
1213{
1036 return false;
1037
1038 // get and keep the y-deltas in the mpDeltaY member variable
1039 // => release it in the destructor
1040 ItemCount nDeltaCount = 0;
1041 OSStatus theErr = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(
1042 maATSULayout, mnMinCharPos, kATSUDirectDataBaselineDeltaFixedArray,
1043 (void**)&mpDeltaY, &nDeltaCount );

--- 151 unchanged lines hidden (view full) ---

1195void ATSLayout::MoveGlyph( int /*nStart*/, long /*nNewXPos*/ ) {}
1196void ATSLayout::DropGlyph( int /*nStart*/ ) {}
1197void ATSLayout::Simplify( bool /*bIsBase*/ ) {}
1198
1199// get the ImplFontData for a glyph fallback font
1200// for a glyphid that was returned by ATSLayout::GetNextGlyphs()
1201const ImplFontData* ATSLayout::GetFallbackFontData( sal_GlyphId aGlyphId ) const
1202{
1214 // check if any fallback fonts were needed
1215 if( !mpFallbackInfo )
1216 return NULL;
1217 // check if the current glyph needs a fallback font
1218 int nFallbackLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
1219 if( !nFallbackLevel )
1220 return NULL;
1203 // check if any fallback fonts were needed
1204 if( !mpFallbackInfo )
1205 return NULL;
1206 // check if the current glyph needs a fallback font
1207 int nFallbackLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
1208 if( !nFallbackLevel )
1209 return NULL;
1221 return mpFallbackInfo->GetFallbackFontData( nFallbackLevel );
1222}
1223
1224// =======================================================================
1225
1226int FallbackInfo::AddFallback( ATSUFontID nFontId )
1227{
1210 return mpFallbackInfo->GetFallbackFontData( nFallbackLevel );
1211}
1212
1213// =======================================================================
1214
1215int FallbackInfo::AddFallback( ATSUFontID nFontId )
1216{
1228 // check if the fallback font is already known
1229 for( int nLevel = 0; nLevel < mnMaxLevel; ++nLevel )
1230 if( maATSUFontId[ nLevel ] == nFontId )
1231 return (nLevel + 1);
1217 // check if the fallback font is already known
1218 for( int nLevel = 0; nLevel < mnMaxLevel; ++nLevel )
1219 if( maATSUFontId[ nLevel ] == nFontId )
1220 return (nLevel + 1);
1232
1233 // append new fallback font if possible
1221
1222 // append new fallback font if possible
1234 if( mnMaxLevel >= MAX_FALLBACK-1 )
1235 return 0;
1236 // keep ATSU font id of fallback font
1237 maATSUFontId[ mnMaxLevel ] = nFontId;
1238 // find and cache the corresponding ImplFontData pointer
1239 const SystemFontList* pSFL = GetSalData()->mpFontList;
1240 const ImplMacFontData* pFontData = pSFL->GetFontDataFromId( nFontId );
1241 maFontData[ mnMaxLevel ] = pFontData;
1242 // increase fallback level by one
1243 return (++mnMaxLevel);
1223 if( mnMaxLevel >= MAX_FALLBACK-1 )
1224 return 0;
1225 // keep ATSU font id of fallback font
1226 maATSUFontId[ mnMaxLevel ] = nFontId;
1227 // find and cache the corresponding ImplFontData pointer
1228 const SystemFontList* pSFL = GetSalData()->mpFontList;
1229 const ImplMacFontData* pFontData = pSFL->GetFontDataFromId( nFontId );
1230 maFontData[ mnMaxLevel ] = pFontData;
1231 // increase fallback level by one
1232 return (++mnMaxLevel);
1244}
1245
1246// -----------------------------------------------------------------------
1247
1248const ImplFontData* FallbackInfo::GetFallbackFontData( int nFallbackLevel ) const
1249{
1233}
1234
1235// -----------------------------------------------------------------------
1236
1237const ImplFontData* FallbackInfo::GetFallbackFontData( int nFallbackLevel ) const
1238{
1250 const ImplMacFontData* pFallbackFont = maFontData[ nFallbackLevel-1 ];
1251 return pFallbackFont;
1239 const ImplMacFontData* pFallbackFont = maFontData[ nFallbackLevel-1 ];
1240 return pFallbackFont;
1252}
1253
1254// =======================================================================
1255
1256SalLayout* AquaSalGraphics::GetTextLayout( ImplLayoutArgs&, int /*nFallbackLevel*/ )
1257{
1241}
1242
1243// =======================================================================
1244
1245SalLayout* AquaSalGraphics::GetTextLayout( ImplLayoutArgs&, int /*nFallbackLevel*/ )
1246{
1258 ATSLayout* pATSLayout = new ATSLayout( maATSUStyle, mfFontScale );
1259 return pATSLayout;
1247 ATSLayout* pATSLayout = new ATSLayout( maATSUStyle, mfFontScale );
1248 return pATSLayout;
1260}
1261
1262// =======================================================================
1263
1249}
1250
1251// =======================================================================
1252