• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "xfa/fxfa/parser/cxfa_rectangle.h"
8 
9 #include <utility>
10 
11 #include "fxjs/xfa/cjx_rectangle.h"
12 #include "third_party/base/ptr_util.h"
13 #include "xfa/fxfa/parser/cxfa_corner.h"
14 #include "xfa/fxfa/parser/cxfa_stroke.h"
15 
16 namespace {
17 
18 const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Edge, 4, 0},
19                                                  {XFA_Element::Corner, 4, 0},
20                                                  {XFA_Element::Fill, 1, 0},
21                                                  {XFA_Element::Unknown, 0, 0}};
22 const CXFA_Node::AttributeData kAttributeData[] = {
23     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
24     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
25     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
26     {XFA_Attribute::Hand, XFA_AttributeType::Enum,
27      (void*)XFA_AttributeEnum::Even},
28     {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
29 
30 constexpr wchar_t kName[] = L"rectangle";
31 
32 }  // namespace
33 
CXFA_Rectangle(CXFA_Document * doc,XFA_PacketType packet)34 CXFA_Rectangle::CXFA_Rectangle(CXFA_Document* doc, XFA_PacketType packet)
35     : CXFA_Box(doc,
36                packet,
37                (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
38                XFA_ObjectType::Node,
39                XFA_Element::Rectangle,
40                kPropertyData,
41                kAttributeData,
42                kName,
43                pdfium::MakeUnique<CJX_Rectangle>(this)) {}
44 
CXFA_Rectangle(CXFA_Document * pDoc,XFA_PacketType ePacket,uint32_t validPackets,XFA_ObjectType oType,XFA_Element eType,const PropertyData * properties,const AttributeData * attributes,const WideStringView & elementName,std::unique_ptr<CJX_Object> js_node)45 CXFA_Rectangle::CXFA_Rectangle(CXFA_Document* pDoc,
46                                XFA_PacketType ePacket,
47                                uint32_t validPackets,
48                                XFA_ObjectType oType,
49                                XFA_Element eType,
50                                const PropertyData* properties,
51                                const AttributeData* attributes,
52                                const WideStringView& elementName,
53                                std::unique_ptr<CJX_Object> js_node)
54     : CXFA_Box(pDoc,
55                ePacket,
56                validPackets,
57                oType,
58                eType,
59                properties,
60                attributes,
61                elementName,
62                std::move(js_node)) {}
63 
~CXFA_Rectangle()64 CXFA_Rectangle::~CXFA_Rectangle() {}
65 
GetFillPath(const std::vector<CXFA_Stroke * > & strokes,const CFX_RectF & rtWidget,CXFA_GEPath * fillPath)66 void CXFA_Rectangle::GetFillPath(const std::vector<CXFA_Stroke*>& strokes,
67                                  const CFX_RectF& rtWidget,
68                                  CXFA_GEPath* fillPath) {
69   bool bSameStyles = true;
70   CXFA_Stroke* stroke1 = strokes[0];
71   for (int32_t i = 1; i < 8; i++) {
72     CXFA_Stroke* stroke2 = strokes[i];
73     if (!stroke1->SameStyles(stroke2, 0)) {
74       bSameStyles = false;
75       break;
76     }
77     stroke1 = stroke2;
78   }
79 
80   if (bSameStyles) {
81     stroke1 = strokes[0];
82     for (int32_t i = 2; i < 8; i += 2) {
83       CXFA_Stroke* stroke2 = strokes[i];
84       if (!stroke1->SameStyles(stroke2, XFA_STROKE_SAMESTYLE_NoPresence |
85                                             XFA_STROKE_SAMESTYLE_Corner)) {
86         bSameStyles = false;
87         break;
88       }
89       stroke1 = stroke2;
90     }
91     if (bSameStyles) {
92       stroke1 = strokes[0];
93       if (stroke1->IsInverted())
94         bSameStyles = false;
95       if (stroke1->GetJoinType() != XFA_AttributeEnum::Square)
96         bSameStyles = false;
97     }
98   }
99   if (bSameStyles) {
100     fillPath->AddRectangle(rtWidget.left, rtWidget.top, rtWidget.width,
101                            rtWidget.height);
102     return;
103   }
104 
105   for (int32_t i = 0; i < 8; i += 2) {
106     float sx = 0.0f;
107     float sy = 0.0f;
108     float vx = 1.0f;
109     float vy = 1.0f;
110     float nx = 1.0f;
111     float ny = 1.0f;
112     CFX_PointF cp1, cp2;
113     auto* corner1 = static_cast<CXFA_Corner*>(strokes[i]);
114     auto* corner2 = static_cast<CXFA_Corner*>(strokes[(i + 2) % 8]);
115     float fRadius1 = corner1->GetRadius();
116     float fRadius2 = corner2->GetRadius();
117     bool bInverted = corner1->IsInverted();
118     bool bRound = corner1->GetJoinType() == XFA_AttributeEnum::Round;
119     if (bRound) {
120       sy = FX_PI / 2;
121     }
122     switch (i) {
123       case 0:
124         cp1 = rtWidget.TopLeft();
125         cp2 = rtWidget.TopRight();
126         vx = 1, vy = 1;
127         nx = -1, ny = 0;
128         if (bRound) {
129           sx = bInverted ? FX_PI / 2 : FX_PI;
130         } else {
131           sx = 1, sy = 0;
132         }
133         break;
134       case 2:
135         cp1 = rtWidget.TopRight();
136         cp2 = rtWidget.BottomRight();
137         vx = -1, vy = 1;
138         nx = 0, ny = -1;
139         if (bRound) {
140           sx = bInverted ? FX_PI : FX_PI * 3 / 2;
141         } else {
142           sx = 0, sy = 1;
143         }
144         break;
145       case 4:
146         cp1 = rtWidget.BottomRight();
147         cp2 = rtWidget.BottomLeft();
148         vx = -1, vy = -1;
149         nx = 1, ny = 0;
150         if (bRound) {
151           sx = bInverted ? FX_PI * 3 / 2 : 0;
152         } else {
153           sx = -1, sy = 0;
154         }
155         break;
156       case 6:
157         cp1 = rtWidget.BottomLeft();
158         cp2 = rtWidget.TopLeft();
159         vx = 1, vy = -1;
160         nx = 0, ny = 1;
161         if (bRound) {
162           sx = bInverted ? 0 : FX_PI / 2;
163         } else {
164           sx = 0;
165           sy = -1;
166         }
167         break;
168     }
169     if (i == 0)
170       fillPath->MoveTo(CFX_PointF(cp1.x, cp1.y + fRadius1));
171 
172     if (bRound) {
173       if (fRadius1 < 0)
174         sx -= FX_PI;
175       if (bInverted)
176         sy *= -1;
177 
178       CFX_RectF rtRadius(cp1.x, cp1.y, fRadius1 * 2 * vx, fRadius1 * 2 * vy);
179       rtRadius.Normalize();
180       if (bInverted)
181         rtRadius.Offset(-fRadius1 * vx, -fRadius1 * vy);
182 
183       fillPath->ArcTo(rtRadius.TopLeft(), rtRadius.Size(), sx, sy);
184     } else {
185       CFX_PointF cp;
186       if (bInverted) {
187         cp.x = cp1.x + fRadius1 * vx;
188         cp.y = cp1.y + fRadius1 * vy;
189       } else {
190         cp = cp1;
191       }
192       fillPath->LineTo(cp);
193       fillPath->LineTo(
194           CFX_PointF(cp1.x + fRadius1 * sx, cp1.y + fRadius1 * sy));
195     }
196     fillPath->LineTo(CFX_PointF(cp2.x + fRadius2 * nx, cp2.y + fRadius2 * ny));
197   }
198 }
199 
Draw(const std::vector<CXFA_Stroke * > & strokes,CXFA_Graphics * pGS,CFX_RectF rtWidget,const CFX_Matrix & matrix)200 void CXFA_Rectangle::Draw(const std::vector<CXFA_Stroke*>& strokes,
201                           CXFA_Graphics* pGS,
202                           CFX_RectF rtWidget,
203                           const CFX_Matrix& matrix) {
204   bool bVisible = false;
205   for (int32_t j = 0; j < 4; j++) {
206     if (strokes[j * 2 + 1]->IsVisible()) {
207       bVisible = true;
208       break;
209     }
210   }
211   if (!bVisible)
212     return;
213 
214   for (int32_t i = 1; i < 8; i += 2) {
215     float fThickness = std::fmax(0.0, strokes[i]->GetThickness());
216     float fHalf = fThickness / 2;
217     XFA_AttributeEnum iHand = GetHand();
218     switch (i) {
219       case 1:
220         if (iHand == XFA_AttributeEnum::Left) {
221           rtWidget.top -= fHalf;
222           rtWidget.height += fHalf;
223         } else if (iHand == XFA_AttributeEnum::Right) {
224           rtWidget.top += fHalf;
225           rtWidget.height -= fHalf;
226         }
227         break;
228       case 3:
229         if (iHand == XFA_AttributeEnum::Left) {
230           rtWidget.width += fHalf;
231         } else if (iHand == XFA_AttributeEnum::Right) {
232           rtWidget.width -= fHalf;
233         }
234         break;
235       case 5:
236         if (iHand == XFA_AttributeEnum::Left) {
237           rtWidget.height += fHalf;
238         } else if (iHand == XFA_AttributeEnum::Right) {
239           rtWidget.height -= fHalf;
240         }
241         break;
242       case 7:
243         if (iHand == XFA_AttributeEnum::Left) {
244           rtWidget.left -= fHalf;
245           rtWidget.width += fHalf;
246         } else if (iHand == XFA_AttributeEnum::Right) {
247           rtWidget.left += fHalf;
248           rtWidget.width -= fHalf;
249         }
250         break;
251     }
252   }
253   Stroke(strokes, pGS, rtWidget, matrix);
254 }
255 
Stroke(const std::vector<CXFA_Stroke * > & strokes,CXFA_Graphics * pGS,CFX_RectF rtWidget,const CFX_Matrix & matrix)256 void CXFA_Rectangle::Stroke(const std::vector<CXFA_Stroke*>& strokes,
257                             CXFA_Graphics* pGS,
258                             CFX_RectF rtWidget,
259                             const CFX_Matrix& matrix) {
260   bool bVisible;
261   float fThickness;
262   XFA_AttributeEnum i3DType;
263   std::tie(i3DType, bVisible, fThickness) = Get3DStyle();
264   if (i3DType != XFA_AttributeEnum::Unknown) {
265     if (!bVisible || fThickness < 0.001f)
266       return;
267 
268     switch (i3DType) {
269       case XFA_AttributeEnum::Lowered:
270         StrokeLowered(pGS, rtWidget, fThickness, matrix);
271         break;
272       case XFA_AttributeEnum::Raised:
273         StrokeRaised(pGS, rtWidget, fThickness, matrix);
274         break;
275       case XFA_AttributeEnum::Etched:
276         StrokeEtched(pGS, rtWidget, fThickness, matrix);
277         break;
278       case XFA_AttributeEnum::Embossed:
279         StrokeEmbossed(pGS, rtWidget, fThickness, matrix);
280         break;
281       default:
282         NOTREACHED();
283         break;
284     }
285     return;
286   }
287 
288   bool bClose = false;
289   bool bSameStyles = true;
290   CXFA_Stroke* stroke1 = strokes[0];
291   for (int32_t i = 1; i < 8; i++) {
292     CXFA_Stroke* stroke2 = strokes[i];
293     if (!stroke1->SameStyles(stroke2, 0)) {
294       bSameStyles = false;
295       break;
296     }
297     stroke1 = stroke2;
298   }
299   if (bSameStyles) {
300     stroke1 = strokes[0];
301     bClose = true;
302     for (int32_t i = 2; i < 8; i += 2) {
303       CXFA_Stroke* stroke2 = strokes[i];
304       if (!stroke1->SameStyles(stroke2, XFA_STROKE_SAMESTYLE_NoPresence |
305                                             XFA_STROKE_SAMESTYLE_Corner)) {
306         bSameStyles = false;
307         break;
308       }
309       stroke1 = stroke2;
310     }
311     if (bSameStyles) {
312       stroke1 = strokes[0];
313       if (stroke1->IsInverted())
314         bSameStyles = false;
315       if (stroke1->GetJoinType() != XFA_AttributeEnum::Square)
316         bSameStyles = false;
317     }
318   }
319 
320   bool bStart = true;
321   CXFA_GEPath path;
322   for (int32_t i = 0; i < 8; i++) {
323     CXFA_Stroke* stroke = strokes[i];
324     if ((i % 1) == 0 && stroke->GetRadius() < 0) {
325       bool bEmpty = path.IsEmpty();
326       if (!bEmpty) {
327         if (stroke)
328           stroke->Stroke(&path, pGS, matrix);
329         path.Clear();
330       }
331       bStart = true;
332       continue;
333     }
334     GetPath(strokes, rtWidget, path, i, bStart, !bSameStyles);
335 
336     bStart = !stroke->SameStyles(strokes[(i + 1) % 8], 0);
337     if (bStart) {
338       if (stroke)
339         stroke->Stroke(&path, pGS, matrix);
340       path.Clear();
341     }
342   }
343   bool bEmpty = path.IsEmpty();
344   if (!bEmpty) {
345     if (bClose) {
346       path.Close();
347     }
348     if (strokes[7])
349       strokes[7]->Stroke(&path, pGS, matrix);
350   }
351 }
352 
StrokeRect(CXFA_Graphics * pGraphic,const CFX_RectF & rt,float fLineWidth,const CFX_Matrix & matrix,FX_ARGB argbTopLeft,FX_ARGB argbBottomRight)353 void CXFA_Rectangle::StrokeRect(CXFA_Graphics* pGraphic,
354                                 const CFX_RectF& rt,
355                                 float fLineWidth,
356                                 const CFX_Matrix& matrix,
357                                 FX_ARGB argbTopLeft,
358                                 FX_ARGB argbBottomRight) {
359   float fBottom = rt.bottom();
360   float fRight = rt.right();
361   CXFA_GEPath pathLT;
362   pathLT.MoveTo(CFX_PointF(rt.left, fBottom));
363   pathLT.LineTo(CFX_PointF(rt.left, rt.top));
364   pathLT.LineTo(CFX_PointF(fRight, rt.top));
365   pathLT.LineTo(CFX_PointF(fRight - fLineWidth, rt.top + fLineWidth));
366   pathLT.LineTo(CFX_PointF(rt.left + fLineWidth, rt.top + fLineWidth));
367   pathLT.LineTo(CFX_PointF(rt.left + fLineWidth, fBottom - fLineWidth));
368   pathLT.LineTo(CFX_PointF(rt.left, fBottom));
369   pGraphic->SetFillColor(CXFA_GEColor(argbTopLeft));
370   pGraphic->FillPath(&pathLT, FXFILL_WINDING, &matrix);
371 
372   CXFA_GEPath pathRB;
373   pathRB.MoveTo(CFX_PointF(fRight, rt.top));
374   pathRB.LineTo(CFX_PointF(fRight, fBottom));
375   pathRB.LineTo(CFX_PointF(rt.left, fBottom));
376   pathRB.LineTo(CFX_PointF(rt.left + fLineWidth, fBottom - fLineWidth));
377   pathRB.LineTo(CFX_PointF(fRight - fLineWidth, fBottom - fLineWidth));
378   pathRB.LineTo(CFX_PointF(fRight - fLineWidth, rt.top + fLineWidth));
379   pathRB.LineTo(CFX_PointF(fRight, rt.top));
380   pGraphic->SetFillColor(CXFA_GEColor(argbBottomRight));
381   pGraphic->FillPath(&pathRB, FXFILL_WINDING, &matrix);
382 }
383 
StrokeLowered(CXFA_Graphics * pGS,CFX_RectF rt,float fThickness,const CFX_Matrix & matrix)384 void CXFA_Rectangle::StrokeLowered(CXFA_Graphics* pGS,
385                                    CFX_RectF rt,
386                                    float fThickness,
387                                    const CFX_Matrix& matrix) {
388   float fHalfWidth = fThickness / 2.0f;
389   CFX_RectF rtInner(rt);
390   rtInner.Deflate(fHalfWidth, fHalfWidth);
391 
392   CXFA_GEPath path;
393   path.AddRectangle(rt.left, rt.top, rt.width, rt.height);
394   path.AddRectangle(rtInner.left, rtInner.top, rtInner.width, rtInner.height);
395   pGS->SetFillColor(CXFA_GEColor(0xFF000000));
396   pGS->FillPath(&path, FXFILL_ALTERNATE, &matrix);
397 
398   StrokeRect(pGS, rtInner, fHalfWidth, matrix, 0xFF808080, 0xFFC0C0C0);
399 }
400 
StrokeRaised(CXFA_Graphics * pGS,CFX_RectF rt,float fThickness,const CFX_Matrix & matrix)401 void CXFA_Rectangle::StrokeRaised(CXFA_Graphics* pGS,
402                                   CFX_RectF rt,
403                                   float fThickness,
404                                   const CFX_Matrix& matrix) {
405   float fHalfWidth = fThickness / 2.0f;
406   CFX_RectF rtInner(rt);
407   rtInner.Deflate(fHalfWidth, fHalfWidth);
408 
409   CXFA_GEPath path;
410   path.AddRectangle(rt.left, rt.top, rt.width, rt.height);
411   path.AddRectangle(rtInner.left, rtInner.top, rtInner.width, rtInner.height);
412   pGS->SetFillColor(CXFA_GEColor(0xFF000000));
413   pGS->FillPath(&path, FXFILL_ALTERNATE, &matrix);
414 
415   StrokeRect(pGS, rtInner, fHalfWidth, matrix, 0xFFFFFFFF, 0xFF808080);
416 }
417 
StrokeEtched(CXFA_Graphics * pGS,CFX_RectF rt,float fThickness,const CFX_Matrix & matrix)418 void CXFA_Rectangle::StrokeEtched(CXFA_Graphics* pGS,
419                                   CFX_RectF rt,
420                                   float fThickness,
421                                   const CFX_Matrix& matrix) {
422   float fHalfWidth = fThickness / 2.0f;
423   StrokeRect(pGS, rt, fThickness, matrix, 0xFF808080, 0xFFFFFFFF);
424 
425   CFX_RectF rtInner(rt);
426   rtInner.Deflate(fHalfWidth, fHalfWidth);
427   StrokeRect(pGS, rtInner, fHalfWidth, matrix, 0xFFFFFFFF, 0xFF808080);
428 }
429 
StrokeEmbossed(CXFA_Graphics * pGS,CFX_RectF rt,float fThickness,const CFX_Matrix & matrix)430 void CXFA_Rectangle::StrokeEmbossed(CXFA_Graphics* pGS,
431                                     CFX_RectF rt,
432                                     float fThickness,
433                                     const CFX_Matrix& matrix) {
434   float fHalfWidth = fThickness / 2.0f;
435   StrokeRect(pGS, rt, fThickness, matrix, 0xFF808080, 0xFF000000);
436 
437   CFX_RectF rtInner(rt);
438   rtInner.Deflate(fHalfWidth, fHalfWidth);
439   StrokeRect(pGS, rtInner, fHalfWidth, matrix, 0xFF000000, 0xFF808080);
440 }
441 
GetPath(const std::vector<CXFA_Stroke * > & strokes,CFX_RectF rtWidget,CXFA_GEPath & path,int32_t nIndex,bool bStart,bool bCorner)442 void CXFA_Rectangle::GetPath(const std::vector<CXFA_Stroke*>& strokes,
443                              CFX_RectF rtWidget,
444                              CXFA_GEPath& path,
445                              int32_t nIndex,
446                              bool bStart,
447                              bool bCorner) {
448   ASSERT(nIndex >= 0 && nIndex < 8);
449 
450   int32_t n = (nIndex & 1) ? nIndex - 1 : nIndex;
451   auto* corner1 = static_cast<CXFA_Corner*>(strokes[n]);
452   auto* corner2 = static_cast<CXFA_Corner*>(strokes[(n + 2) % 8]);
453   float fRadius1 = bCorner ? corner1->GetRadius() : 0.0f;
454   float fRadius2 = bCorner ? corner2->GetRadius() : 0.0f;
455   bool bInverted = corner1->IsInverted();
456   float offsetY = 0.0f;
457   float offsetX = 0.0f;
458   bool bRound = corner1->GetJoinType() == XFA_AttributeEnum::Round;
459   float halfAfter = 0.0f;
460   float halfBefore = 0.0f;
461 
462   CXFA_Stroke* stroke = strokes[nIndex];
463   if (stroke->IsCorner()) {
464     CXFA_Stroke* strokeBefore = strokes[(nIndex + 1 * 8 - 1) % 8];
465     CXFA_Stroke* strokeAfter = strokes[nIndex + 1];
466     if (stroke->IsInverted()) {
467       if (!stroke->SameStyles(strokeBefore, 0))
468         halfBefore = strokeBefore->GetThickness() / 2;
469       if (!stroke->SameStyles(strokeAfter, 0))
470         halfAfter = strokeAfter->GetThickness() / 2;
471     }
472   } else {
473     CXFA_Stroke* strokeBefore = strokes[(nIndex + 8 - 2) % 8];
474     CXFA_Stroke* strokeAfter = strokes[(nIndex + 2) % 8];
475     if (!bRound && !bInverted) {
476       halfBefore = strokeBefore->GetThickness() / 2;
477       halfAfter = strokeAfter->GetThickness() / 2;
478     }
479   }
480 
481   float offsetEX = 0.0f;
482   float offsetEY = 0.0f;
483   float sx = 0.0f;
484   float sy = 0.0f;
485   float vx = 1.0f;
486   float vy = 1.0f;
487   float nx = 1.0f;
488   float ny = 1.0f;
489   CFX_PointF cpStart;
490   CFX_PointF cp1;
491   CFX_PointF cp2;
492   if (bRound)
493     sy = FX_PI / 2;
494 
495   switch (nIndex) {
496     case 0:
497     case 1:
498       cp1 = rtWidget.TopLeft();
499       cp2 = rtWidget.TopRight();
500       if (nIndex == 0) {
501         cpStart.x = cp1.x - halfBefore;
502         cpStart.y = cp1.y + fRadius1, offsetY = -halfAfter;
503       } else {
504         cpStart.x = cp1.x + fRadius1 - halfBefore, cpStart.y = cp1.y,
505         offsetEX = halfAfter;
506       }
507       vx = 1, vy = 1;
508       nx = -1, ny = 0;
509       if (bRound) {
510         sx = bInverted ? FX_PI / 2 : FX_PI;
511       } else {
512         sx = 1, sy = 0;
513       }
514       break;
515     case 2:
516     case 3:
517       cp1 = rtWidget.TopRight();
518       cp2 = rtWidget.BottomRight();
519       if (nIndex == 2) {
520         cpStart.x = cp1.x - fRadius1, cpStart.y = cp1.y - halfBefore,
521         offsetX = halfAfter;
522       } else {
523         cpStart.x = cp1.x, cpStart.y = cp1.y + fRadius1 - halfBefore,
524         offsetEY = halfAfter;
525       }
526       vx = -1, vy = 1;
527       nx = 0, ny = -1;
528       if (bRound) {
529         sx = bInverted ? FX_PI : FX_PI * 3 / 2;
530       } else {
531         sx = 0, sy = 1;
532       }
533       break;
534     case 4:
535     case 5:
536       cp1 = rtWidget.BottomRight();
537       cp2 = rtWidget.BottomLeft();
538       if (nIndex == 4) {
539         cpStart.x = cp1.x + halfBefore, cpStart.y = cp1.y - fRadius1,
540         offsetY = halfAfter;
541       } else {
542         cpStart.x = cp1.x - fRadius1 + halfBefore, cpStart.y = cp1.y,
543         offsetEX = -halfAfter;
544       }
545       vx = -1, vy = -1;
546       nx = 1, ny = 0;
547       if (bRound) {
548         sx = bInverted ? FX_PI * 3 / 2 : 0;
549       } else {
550         sx = -1, sy = 0;
551       }
552       break;
553     case 6:
554     case 7:
555       cp1 = rtWidget.BottomLeft();
556       cp2 = rtWidget.TopLeft();
557       if (nIndex == 6) {
558         cpStart.x = cp1.x + fRadius1, cpStart.y = cp1.y + halfBefore,
559         offsetX = -halfAfter;
560       } else {
561         cpStart.x = cp1.x, cpStart.y = cp1.y - fRadius1 + halfBefore,
562         offsetEY = -halfAfter;
563       }
564       vx = 1;
565       vy = -1;
566       nx = 0;
567       ny = 1;
568       if (bRound) {
569         sx = bInverted ? 0 : FX_PI / 2;
570       } else {
571         sx = 0;
572         sy = -1;
573       }
574       break;
575   }
576   if (bStart) {
577     path.MoveTo(cpStart);
578   }
579   if (nIndex & 1) {
580     path.LineTo(CFX_PointF(cp2.x + fRadius2 * nx + offsetEX,
581                            cp2.y + fRadius2 * ny + offsetEY));
582     return;
583   }
584   if (bRound) {
585     if (fRadius1 < 0)
586       sx -= FX_PI;
587     if (bInverted)
588       sy *= -1;
589 
590     CFX_RectF rtRadius(cp1.x + offsetX * 2, cp1.y + offsetY * 2,
591                        fRadius1 * 2 * vx - offsetX * 2,
592                        fRadius1 * 2 * vy - offsetY * 2);
593     rtRadius.Normalize();
594     if (bInverted)
595       rtRadius.Offset(-fRadius1 * vx, -fRadius1 * vy);
596 
597     path.ArcTo(rtRadius.TopLeft(), rtRadius.Size(), sx, sy);
598   } else {
599     CFX_PointF cp;
600     if (bInverted) {
601       cp.x = cp1.x + fRadius1 * vx;
602       cp.y = cp1.y + fRadius1 * vy;
603     } else {
604       cp = cp1;
605     }
606     path.LineTo(cp);
607     path.LineTo(CFX_PointF(cp1.x + fRadius1 * sx + offsetX,
608                            cp1.y + fRadius1 * sy + offsetY));
609   }
610 }
611