bump product version to 6.3.0.0.beta1
[LibreOffice.git] / cppcanvas / source / mtfrenderer / mtftools.cxx
blob1a561631939db14b94971383988e71027af6ed7e
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 .
21 #include <tools/diagnose_ex.h>
22 #include <com/sun/star/rendering/RenderState.hpp>
23 #include <com/sun/star/rendering/XCanvas.hpp>
24 #include <basegfx/numeric/ftools.hxx>
25 #include <basegfx/utils/canvastools.hxx>
26 #include <basegfx/polygon/b2dpolygontools.hxx>
27 #include <basegfx/polygon/b2dpolygon.hxx>
28 #include <basegfx/range/b2drectangle.hxx>
29 #include <basegfx/vector/b2dvector.hxx>
30 #include <canvas/canvastools.hxx>
31 #include <vcl/canvastools.hxx>
32 #include <vcl/gdimtf.hxx>
33 #include <vcl/metaact.hxx>
34 #include <vcl/virdev.hxx>
35 #include <vcl/metric.hxx>
36 #include <tools/poly.hxx>
37 #include "mtftools.hxx"
38 #include <outdevstate.hxx>
39 #include "polypolyaction.hxx"
40 #include <basegfx/matrix/b2dhommatrixtools.hxx>
43 using namespace ::com::sun::star;
45 namespace cppcanvas
47 namespace tools
49 void initRenderState( rendering::RenderState& renderState,
50 const ::cppcanvas::internal::OutDevState& outdevState )
52 ::canvas::tools::initRenderState( renderState );
53 ::canvas::tools::setRenderStateTransform( renderState,
54 outdevState.transform );
55 renderState.Clip = outdevState.xClipPoly;
58 ::Size getBaselineOffset( const ::cppcanvas::internal::OutDevState& outdevState,
59 const VirtualDevice& rVDev )
61 const ::FontMetric& aMetric = rVDev.GetFontMetric();
63 // calc offset for text output, the XCanvas always renders
64 // baseline offset.
65 switch( outdevState.textReferencePoint )
67 case ALIGN_TOP:
68 return ::Size( 0,
69 aMetric.GetInternalLeading() + aMetric.GetAscent() );
71 default:
72 ENSURE_OR_THROW( false,
73 "tools::getBaselineOffset(): Unexpected TextAlign value" );
74 // FALLTHROUGH intended (to calm compiler warning - case won't happen)
75 case ALIGN_BASELINE:
76 return ::Size( 0, 0 );
78 case ALIGN_BOTTOM:
79 return ::Size( 0,
80 -aMetric.GetDescent() );
85 ::basegfx::B2DHomMatrix& calcLogic2PixelLinearTransform( ::basegfx::B2DHomMatrix& o_rMatrix,
86 const VirtualDevice& rVDev )
88 // select size value in the middle of the available range,
89 // to have headroom both when map mode scales up, and when
90 // it scales down.
91 const ::Size aSizeLogic( 0x00010000L,
92 0x00010000L );
94 const ::Size aSizePixel( rVDev.LogicToPixel( aSizeLogic ) );
96 o_rMatrix = basegfx::utils::createScaleB2DHomMatrix(
97 aSizePixel.Width() / static_cast<double>(aSizeLogic.Width()),
98 aSizePixel.Height() / static_cast<double>(aSizeLogic.Height()) );
100 return o_rMatrix;
103 ::basegfx::B2DHomMatrix& calcLogic2PixelAffineTransform( ::basegfx::B2DHomMatrix& o_rMatrix,
104 const VirtualDevice& rVDev )
106 // retrieves scale
107 calcLogic2PixelLinearTransform(o_rMatrix, rVDev);
109 // translate according to curr map mode/pref map mode offset
110 const ::Point aEmptyPoint;
111 const ::Point& rTranslatedPoint(
112 rVDev.LogicToPixel( aEmptyPoint ));
114 o_rMatrix.translate(rTranslatedPoint.X(),
115 rTranslatedPoint.Y());
117 return o_rMatrix;
120 bool modifyClip( rendering::RenderState& o_rRenderState,
121 const struct ::cppcanvas::internal::OutDevState& rOutdevState,
122 const CanvasSharedPtr& rCanvas,
123 const ::basegfx::B2DPoint& rOffset,
124 const ::basegfx::B2DVector* pScaling,
125 const double* pRotation )
127 const bool bOffsetting( !rOffset.equalZero() );
128 const bool bScaling( pScaling &&
129 !rtl::math::approxEqual(pScaling->getX(), 1.0) &&
130 !rtl::math::approxEqual(pScaling->getY(), 1.0) );
131 const bool bRotation( pRotation &&
132 *pRotation != 0.0 );
134 if( !bOffsetting && !bScaling && !bRotation )
135 return false; // nothing to do
137 if( rOutdevState.clip.count() )
139 // general polygon case
141 ::basegfx::B2DPolyPolygon aLocalClip( rOutdevState.clip );
142 ::basegfx::B2DHomMatrix aTransform;
144 if( bOffsetting )
145 aTransform.translate( -rOffset.getX(),
146 -rOffset.getY() );
147 if( bScaling )
148 aTransform.scale( 1.0/pScaling->getX(), 1.0/pScaling->getY() );
150 if( bRotation )
151 aTransform.rotate( - *pRotation );
153 aLocalClip.transform( aTransform );
155 o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
156 rCanvas->getUNOCanvas()->getDevice(),
157 aLocalClip );
159 return true;
161 else if( !rOutdevState.clipRect.IsEmpty() )
163 // simple rect case
165 const ::tools::Rectangle aLocalClipRect( rOutdevState.clipRect );
167 if( bRotation )
169 // rotation involved - convert to polygon first,
170 // then transform that
171 ::basegfx::B2DPolygon aLocalClip(
172 ::basegfx::utils::createPolygonFromRect(
173 vcl::unotools::b2DRectangleFromRectangle(aLocalClipRect) ) );
174 ::basegfx::B2DHomMatrix aTransform;
176 if( bOffsetting )
177 aTransform.translate( -rOffset.getX(),
178 -rOffset.getY() );
179 if( bScaling )
180 aTransform.scale( 1.0/pScaling->getX(), 1.0/pScaling->getY() );
182 aTransform.rotate( - *pRotation );
184 aLocalClip.transform( aTransform );
186 o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
187 rCanvas->getUNOCanvas()->getDevice(),
188 ::basegfx::B2DPolyPolygon( aLocalClip ) );
190 else if( bScaling )
192 // scale and offset - do it on the fly, have to
193 // convert to float anyway.
194 o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
195 rCanvas->getUNOCanvas()->getDevice(),
196 ::basegfx::B2DPolyPolygon(
197 ::basegfx::utils::createPolygonFromRect(
198 ::basegfx::B2DRectangle(
199 (aLocalClipRect.Left() - rOffset.getX())/pScaling->getX(),
200 (aLocalClipRect.Top() - rOffset.getY())/pScaling->getY(),
201 (aLocalClipRect.Right() - rOffset.getX())/pScaling->getX(),
202 (aLocalClipRect.Bottom() - rOffset.getY())/pScaling->getY() ) ) ) );
204 else
206 // offset only - do it on the fly, have to convert
207 // to float anyway.
208 o_rRenderState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
209 rCanvas->getUNOCanvas()->getDevice(),
210 ::basegfx::B2DPolyPolygon(
211 ::basegfx::utils::createPolygonFromRect(
212 ::basegfx::B2DRectangle( aLocalClipRect.Left() - rOffset.getX(),
213 aLocalClipRect.Top() - rOffset.getY(),
214 aLocalClipRect.Right() - rOffset.getX(),
215 aLocalClipRect.Bottom() - rOffset.getY() ) ) ) );
218 return true;
221 // empty clip, nothing to do
222 return false;
225 // create overline/underline/strikeout line info struct
226 TextLineInfo createTextLineInfo( const ::VirtualDevice& rVDev,
227 const ::cppcanvas::internal::OutDevState& rState )
229 const bool bOldMode( rVDev.IsMapModeEnabled() );
231 // #i68512# Force metric regeneration with mapmode enabled
232 // (prolly OutDev bug)
233 rVDev.GetFontMetric();
235 // will restore map mode below
236 const_cast< ::VirtualDevice& >(rVDev).EnableMapMode( false );
238 const ::FontMetric aMetric = rVDev.GetFontMetric();
240 TextLineInfo aTextInfo(
241 (aMetric.GetDescent() + 2) / 4.0,
242 ((aMetric.GetInternalLeading() + 1.5) / 3.0),
243 (aMetric.GetInternalLeading() / 2.0) - aMetric.GetAscent(),
244 aMetric.GetDescent() / 2.0,
245 (aMetric.GetInternalLeading() - aMetric.GetAscent()) / 3.0,
246 rState.textOverlineStyle,
247 rState.textUnderlineStyle,
248 rState.textStrikeoutStyle );
250 const_cast< ::VirtualDevice& >(rVDev).EnableMapMode( bOldMode );
252 return aTextInfo;
255 namespace
257 void appendWaveline( ::basegfx::B2DPolyPolygon& o_rPoly,
258 const ::basegfx::B2DPoint& rStartPos,
259 const double nStartOffset,
260 const double nWidth,
261 const double nHeight,
262 sal_Int8 nLineStyle)
264 const double x(rStartPos.getX());
265 const double y(rStartPos.getY() + nStartOffset + nHeight);
266 double nWaveWidth = nHeight * 10.6 * 0.25;
267 // Offset for the double line.
268 double nOffset = 0.0;
270 if (nLineStyle == LINESTYLE_DOUBLEWAVE)
271 nOffset = -nHeight * 0.5;
272 else
273 nWaveWidth *= 2.0;
275 basegfx::B2DPolygon aLine;
276 aLine.append(basegfx::B2DPoint(x, y + nOffset));
277 aLine.append(basegfx::B2DPoint(x + nWidth, y + nOffset));
279 o_rPoly.append(::basegfx::utils::createWaveline(aLine, nWaveWidth, nWaveWidth * 0.5));
281 if (nLineStyle == LINESTYLE_DOUBLEWAVE)
283 nOffset = nHeight * 1.2;
285 basegfx::B2DPolygon aLine2;
286 aLine2.append(basegfx::B2DPoint(x, y + nOffset));
287 aLine2.append(basegfx::B2DPoint(x + nWidth, y + nOffset));
288 o_rPoly.append(::basegfx::utils::createWaveline(aLine2, nWaveWidth, nWaveWidth * 0.5));
292 void appendRect( ::basegfx::B2DPolyPolygon& o_rPoly,
293 const ::basegfx::B2DPoint& rStartPos,
294 const double nX1,
295 const double nY1,
296 const double nX2,
297 const double nY2 )
299 const double x( rStartPos.getX() );
300 const double y( rStartPos.getY() );
302 o_rPoly.append(
303 ::basegfx::utils::createPolygonFromRect(
304 ::basegfx::B2DRectangle( x + nX1, y + nY1, x + nX2, y + nY2 ) ) );
307 void appendRect( ::basegfx::B2DPolyPolygon& o_rPoly,
308 const double nX1,
309 const double nY1,
310 const double nX2,
311 const double nY2 )
313 o_rPoly.append(
314 ::basegfx::utils::createPolygonFromRect(
315 ::basegfx::B2DRectangle( nX1, nY1, nX2, nY2 ) ) );
318 bool appendDashes( ::basegfx::B2DPolyPolygon& o_rPoly,
319 const double nX,
320 double nY,
321 const double nLineWidth,
322 double nLineHeight,
323 sal_Int8 nLineStyle,
324 bool bIsOverline)
326 static const int aDottedArray[] = { 1, 1, 0}; // DOTTED LINE
327 static const int aDotDashArray[] = { 1, 1, 4, 1, 0}; // DASHDOT
328 static const int aDashDotDotArray[] = { 1, 1, 1, 1, 4, 1, 0}; // DASHDOTDOT
329 static const int aDashedArray[] = { 5, 2, 0}; // DASHED LINE
330 static const int aLongDashArray[] = { 7, 2, 0}; // LONGDASH
331 const int *pArray = nullptr;
332 bool bIsBold = false;
334 switch(nLineStyle)
336 case LINESTYLE_BOLDDOTTED:
337 bIsBold = true;
338 [[fallthrough]];
339 case LINESTYLE_DOTTED:
340 pArray = aDottedArray;
341 break;
343 case LINESTYLE_BOLDDASH:
344 bIsBold = true;
345 [[fallthrough]];
346 case LINESTYLE_DASH:
347 pArray = aDashedArray;
348 break;
350 case LINESTYLE_BOLDLONGDASH:
351 bIsBold = true;
352 [[fallthrough]];
353 case LINESTYLE_LONGDASH:
354 pArray = aLongDashArray;
355 break;
357 case LINESTYLE_BOLDDASHDOT:
358 bIsBold = true;
359 [[fallthrough]];
360 case LINESTYLE_DASHDOT:
361 pArray = aDotDashArray;
362 break;
363 case LINESTYLE_BOLDDASHDOTDOT:
364 bIsBold = true;
365 [[fallthrough]];
366 case LINESTYLE_DASHDOTDOT:
367 pArray = aDashDotDotArray;
368 break;
371 if (!pArray)
372 return false;
374 if (bIsBold)
376 if (bIsOverline)
377 nY -= nLineHeight;
379 nLineHeight *= 2;
382 const double nEnd = nX + nLineWidth;
383 sal_Int32 nIndex = 0;
384 bool bAppend = true;
385 double nX1 = nX;
387 while(nX1 < nEnd)
389 if (pArray[nIndex] == 0)
390 nIndex = 0;
392 const double nX2 = std::min(nEnd, nX1 + pArray[nIndex] * nLineHeight);
394 if (bAppend)
395 appendRect(o_rPoly, nX1, nY, nX2, nY + nLineHeight);
397 nX1 = nX2;
399 ++nIndex;
401 bAppend = !bAppend;
403 return true;
406 // create line actions for text such as underline and
407 // strikeout
408 void createOverlinePolyPolygon(::basegfx::B2DPolyPolygon& rTextLinesPolyPoly,
409 const ::basegfx::B2DPoint& rStartPos,
410 const double& rLineWidth,
411 const TextLineInfo& rTextLineInfo)
413 switch( rTextLineInfo.mnOverlineStyle )
415 case LINESTYLE_NONE: // nothing to do
416 case LINESTYLE_DONTKNOW:
417 break;
419 case LINESTYLE_DOUBLEWAVE:
420 case LINESTYLE_SMALLWAVE:
421 case LINESTYLE_BOLDWAVE:
422 case LINESTYLE_WAVE:
423 appendWaveline(
424 rTextLinesPolyPoly,
425 rStartPos,
426 rTextLineInfo.mnOverlineOffset,
427 rLineWidth,
428 rTextLineInfo.mnOverlineHeight,
429 rTextLineInfo.mnOverlineStyle);
431 break;
432 case LINESTYLE_SINGLE:
433 appendRect(
434 rTextLinesPolyPoly,
435 rStartPos,
437 rTextLineInfo.mnOverlineOffset,
438 rLineWidth,
439 rTextLineInfo.mnOverlineOffset + rTextLineInfo.mnOverlineHeight );
440 break;
441 case LINESTYLE_BOLD:
442 appendRect(
443 rTextLinesPolyPoly,
444 rStartPos,
446 rTextLineInfo.mnOverlineOffset - rTextLineInfo.mnOverlineHeight,
447 rLineWidth,
448 rTextLineInfo.mnOverlineOffset + rTextLineInfo.mnOverlineHeight );
449 break;
451 case LINESTYLE_DOUBLE:
452 appendRect(
453 rTextLinesPolyPoly,
454 rStartPos,
456 rTextLineInfo.mnOverlineOffset - rTextLineInfo.mnOverlineHeight * 2.0 ,
457 rLineWidth,
458 rTextLineInfo.mnOverlineOffset - rTextLineInfo.mnOverlineHeight );
460 appendRect(
461 rTextLinesPolyPoly,
462 rStartPos,
464 rTextLineInfo.mnOverlineOffset + rTextLineInfo.mnOverlineHeight,
465 rLineWidth,
466 rTextLineInfo.mnOverlineOffset + rTextLineInfo.mnOverlineHeight * 2.0 );
467 break;
469 default:
470 if (!appendDashes(
471 rTextLinesPolyPoly,
472 rStartPos.getX(),
473 rStartPos.getY() + rTextLineInfo.mnOverlineOffset,
474 rLineWidth,
475 rTextLineInfo.mnOverlineHeight,
476 rTextLineInfo.mnOverlineStyle,
477 true))
479 ENSURE_OR_THROW( false,
480 "::cppcanvas::internal::createTextLinesPolyPolygon(): Unexpected overline case" );
485 void createUnderlinePolyPolygon(::basegfx::B2DPolyPolygon& rTextLinesPolyPoly,
486 const ::basegfx::B2DPoint& rStartPos,
487 const double& rLineWidth,
488 const TextLineInfo& rTextLineInfo )
491 switch( rTextLineInfo.mnUnderlineStyle )
493 case LINESTYLE_NONE: // nothing to do
494 case LINESTYLE_DONTKNOW:
495 break;
497 case LINESTYLE_DOUBLEWAVE:
498 case LINESTYLE_SMALLWAVE:
499 case LINESTYLE_BOLDWAVE:
500 case LINESTYLE_WAVE:
501 appendWaveline(
502 rTextLinesPolyPoly,
503 rStartPos,
504 rTextLineInfo.mnUnderlineOffset,
505 rLineWidth,
506 rTextLineInfo.mnLineHeight,
507 rTextLineInfo.mnUnderlineStyle);
508 break;
509 case LINESTYLE_SINGLE:
510 appendRect(
511 rTextLinesPolyPoly,
512 rStartPos,
514 rTextLineInfo.mnUnderlineOffset,
515 rLineWidth,
516 rTextLineInfo.mnUnderlineOffset + rTextLineInfo.mnLineHeight );
517 break;
519 case LINESTYLE_BOLD:
520 appendRect(
521 rTextLinesPolyPoly,
522 rStartPos,
524 rTextLineInfo.mnUnderlineOffset,
525 rLineWidth,
526 rTextLineInfo.mnUnderlineOffset + 2*rTextLineInfo.mnLineHeight );
527 break;
529 case LINESTYLE_DOUBLE:
530 appendRect(
531 rTextLinesPolyPoly,
532 rStartPos,
534 rTextLineInfo.mnUnderlineOffset - rTextLineInfo.mnLineHeight,
535 rLineWidth,
536 rTextLineInfo.mnUnderlineOffset );
538 appendRect(
539 rTextLinesPolyPoly,
540 rStartPos,
542 rTextLineInfo.mnUnderlineOffset + 2*rTextLineInfo.mnLineHeight,
543 rLineWidth,
544 rTextLineInfo.mnUnderlineOffset + 3*rTextLineInfo.mnLineHeight );
545 break;
547 default:
548 if (!appendDashes(
549 rTextLinesPolyPoly,
550 rStartPos.getX(),
551 rStartPos.getY() + rTextLineInfo.mnUnderlineOffset,
552 rLineWidth,
553 rTextLineInfo.mnLineHeight,
554 rTextLineInfo.mnUnderlineStyle,
555 false))
557 ENSURE_OR_THROW( false,
558 "::cppcanvas::internal::createTextLinesPolyPolygon(): Unexpected underline case" );
563 void createStrikeoutPolyPolygon(::basegfx::B2DPolyPolygon& rTextLinesPolyPoly,
564 const ::basegfx::B2DPoint& rStartPos,
565 const double& rLineWidth,
566 const TextLineInfo& rTextLineInfo)
568 switch( rTextLineInfo.mnStrikeoutStyle )
570 case STRIKEOUT_NONE: // nothing to do
571 case STRIKEOUT_DONTKNOW:
572 break;
574 case STRIKEOUT_SLASH: // TODO(Q1): we should handle this in the text layer
575 case STRIKEOUT_X:
576 break;
578 case STRIKEOUT_SINGLE:
579 appendRect(
580 rTextLinesPolyPoly,
581 rStartPos,
583 rTextLineInfo.mnStrikeoutOffset,
584 rLineWidth,
585 rTextLineInfo.mnStrikeoutOffset + rTextLineInfo.mnLineHeight );
586 break;
588 case STRIKEOUT_BOLD:
589 appendRect(
590 rTextLinesPolyPoly,
591 rStartPos,
593 rTextLineInfo.mnStrikeoutOffset,
594 rLineWidth,
595 rTextLineInfo.mnStrikeoutOffset + 2*rTextLineInfo.mnLineHeight );
596 break;
598 case STRIKEOUT_DOUBLE:
599 appendRect(
600 rTextLinesPolyPoly,
601 rStartPos,
603 rTextLineInfo.mnStrikeoutOffset - rTextLineInfo.mnLineHeight,
604 rLineWidth,
605 rTextLineInfo.mnStrikeoutOffset );
607 appendRect(
608 rTextLinesPolyPoly,
609 rStartPos,
611 rTextLineInfo.mnStrikeoutOffset + 2*rTextLineInfo.mnLineHeight,
612 rLineWidth,
613 rTextLineInfo.mnStrikeoutOffset + 3*rTextLineInfo.mnLineHeight );
614 break;
616 default:
617 ENSURE_OR_THROW( false,
618 "::cppcanvas::internal::createTextLinesPolyPolygon(): Unexpected strikeout case" );
623 ::basegfx::B2DPolyPolygon createTextLinesPolyPolygon( const ::basegfx::B2DPoint& rStartPos,
624 const double& rLineWidth,
625 const TextLineInfo& rTextLineInfo )
627 // fill the polypolygon with all text lines
628 ::basegfx::B2DPolyPolygon aTextLinesPolyPoly;
630 createOverlinePolyPolygon(aTextLinesPolyPoly, rStartPos, rLineWidth, rTextLineInfo);
631 createUnderlinePolyPolygon(aTextLinesPolyPoly, rStartPos, rLineWidth, rTextLineInfo);
632 createStrikeoutPolyPolygon(aTextLinesPolyPoly, rStartPos, rLineWidth, rTextLineInfo);
633 return aTextLinesPolyPoly;
636 ::basegfx::B2DRange calcDevicePixelBounds( const ::basegfx::B2DRange& rBounds,
637 const rendering::ViewState& viewState,
638 const rendering::RenderState& renderState )
640 ::basegfx::B2DHomMatrix aTransform;
641 ::canvas::tools::mergeViewAndRenderTransform( aTransform,
642 viewState,
643 renderState );
645 ::basegfx::B2DRange aTransformedBounds;
646 return ::canvas::tools::calcTransformedRectBounds( aTransformedBounds,
647 rBounds,
648 aTransform );
651 // create line actions for text such as underline and
652 // strikeout
653 ::basegfx::B2DPolyPolygon createTextLinesPolyPolygon( const double& rStartOffset,
654 const double& rLineWidth,
655 const TextLineInfo& rTextLineInfo )
657 return createTextLinesPolyPolygon(
658 ::basegfx::B2DPoint( rStartOffset,
659 0.0 ),
660 rLineWidth,
661 rTextLineInfo );
664 void createTextLinesPolyPolygon( const double& rStartOffset,
665 const double& rLineWidth,
666 const TextLineInfo& rTextLineInfo,
667 ::basegfx::B2DPolyPolygon& rOverlinePolyPoly,
668 ::basegfx::B2DPolyPolygon& rUnderlinePolyPoly,
669 ::basegfx::B2DPolyPolygon& rStrikeoutPolyPoly )
671 ::basegfx::B2DPoint aStartPos(rStartOffset, 0.0);
673 createOverlinePolyPolygon(rOverlinePolyPoly, aStartPos, rLineWidth, rTextLineInfo);
674 createUnderlinePolyPolygon(rUnderlinePolyPoly, aStartPos, rLineWidth, rTextLineInfo);
675 createStrikeoutPolyPolygon(rStrikeoutPolyPoly, aStartPos, rLineWidth, rTextLineInfo);
680 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */