You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
610 lines
18 KiB
610 lines
18 KiB
// Copyright 2017 PDFium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
|
|
|
|
#include "xfa/fxfa/parser/cxfa_rectangle.h"
|
|
|
|
#include <utility>
|
|
|
|
#include "core/fxge/render_defines.h"
|
|
#include "fxjs/xfa/cjx_node.h"
|
|
#include "third_party/base/ptr_util.h"
|
|
#include "xfa/fxfa/parser/cxfa_corner.h"
|
|
#include "xfa/fxfa/parser/cxfa_stroke.h"
|
|
|
|
namespace {
|
|
|
|
const CXFA_Node::PropertyData kRectanglePropertyData[] = {
|
|
{XFA_Element::Edge, 4, 0},
|
|
{XFA_Element::Corner, 4, 0},
|
|
{XFA_Element::Fill, 1, 0},
|
|
};
|
|
|
|
const CXFA_Node::AttributeData kRectangleAttributeData[] = {
|
|
{XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
|
|
{XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
|
|
{XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
|
|
{XFA_Attribute::Hand, XFA_AttributeType::Enum,
|
|
(void*)XFA_AttributeValue::Even},
|
|
};
|
|
|
|
} // namespace
|
|
|
|
CXFA_Rectangle::CXFA_Rectangle(CXFA_Document* doc, XFA_PacketType packet)
|
|
: CXFA_Box(doc,
|
|
packet,
|
|
(XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
|
|
XFA_ObjectType::Node,
|
|
XFA_Element::Rectangle,
|
|
kRectanglePropertyData,
|
|
kRectangleAttributeData,
|
|
pdfium::MakeUnique<CJX_Node>(this)) {}
|
|
|
|
CXFA_Rectangle::CXFA_Rectangle(CXFA_Document* pDoc,
|
|
XFA_PacketType ePacket,
|
|
uint32_t validPackets,
|
|
XFA_ObjectType oType,
|
|
XFA_Element eType,
|
|
pdfium::span<const PropertyData> properties,
|
|
pdfium::span<const AttributeData> attributes,
|
|
std::unique_ptr<CJX_Object> js_node)
|
|
: CXFA_Box(pDoc,
|
|
ePacket,
|
|
validPackets,
|
|
oType,
|
|
eType,
|
|
properties,
|
|
attributes,
|
|
std::move(js_node)) {}
|
|
|
|
CXFA_Rectangle::~CXFA_Rectangle() {}
|
|
|
|
void CXFA_Rectangle::GetFillPath(const std::vector<CXFA_Stroke*>& strokes,
|
|
const CFX_RectF& rtWidget,
|
|
CXFA_GEPath* fillPath) {
|
|
bool bSameStyles = true;
|
|
CXFA_Stroke* stroke1 = strokes[0];
|
|
for (int32_t i = 1; i < 8; i++) {
|
|
CXFA_Stroke* stroke2 = strokes[i];
|
|
if (!stroke1->SameStyles(stroke2, 0)) {
|
|
bSameStyles = false;
|
|
break;
|
|
}
|
|
stroke1 = stroke2;
|
|
}
|
|
|
|
if (bSameStyles) {
|
|
stroke1 = strokes[0];
|
|
for (int32_t i = 2; i < 8; i += 2) {
|
|
CXFA_Stroke* stroke2 = strokes[i];
|
|
if (!stroke1->SameStyles(stroke2, XFA_STROKE_SAMESTYLE_NoPresence |
|
|
XFA_STROKE_SAMESTYLE_Corner)) {
|
|
bSameStyles = false;
|
|
break;
|
|
}
|
|
stroke1 = stroke2;
|
|
}
|
|
if (bSameStyles) {
|
|
stroke1 = strokes[0];
|
|
if (stroke1->IsInverted())
|
|
bSameStyles = false;
|
|
if (stroke1->GetJoinType() != XFA_AttributeValue::Square)
|
|
bSameStyles = false;
|
|
}
|
|
}
|
|
if (bSameStyles) {
|
|
fillPath->AddRectangle(rtWidget.left, rtWidget.top, rtWidget.width,
|
|
rtWidget.height);
|
|
return;
|
|
}
|
|
|
|
for (int32_t i = 0; i < 8; i += 2) {
|
|
float sx = 0.0f;
|
|
float sy = 0.0f;
|
|
float vx = 1.0f;
|
|
float vy = 1.0f;
|
|
float nx = 1.0f;
|
|
float ny = 1.0f;
|
|
CFX_PointF cp1, cp2;
|
|
CXFA_Stroke* corner1 = strokes[i];
|
|
CXFA_Stroke* corner2 = strokes[(i + 2) % 8];
|
|
float fRadius1 = corner1->GetRadius();
|
|
float fRadius2 = corner2->GetRadius();
|
|
bool bInverted = corner1->IsInverted();
|
|
bool bRound = corner1->GetJoinType() == XFA_AttributeValue::Round;
|
|
if (bRound) {
|
|
sy = FX_PI / 2;
|
|
}
|
|
switch (i) {
|
|
case 0:
|
|
cp1 = rtWidget.TopLeft();
|
|
cp2 = rtWidget.TopRight();
|
|
vx = 1, vy = 1;
|
|
nx = -1, ny = 0;
|
|
if (bRound) {
|
|
sx = bInverted ? FX_PI / 2 : FX_PI;
|
|
} else {
|
|
sx = 1, sy = 0;
|
|
}
|
|
break;
|
|
case 2:
|
|
cp1 = rtWidget.TopRight();
|
|
cp2 = rtWidget.BottomRight();
|
|
vx = -1, vy = 1;
|
|
nx = 0, ny = -1;
|
|
if (bRound) {
|
|
sx = bInverted ? FX_PI : FX_PI * 3 / 2;
|
|
} else {
|
|
sx = 0, sy = 1;
|
|
}
|
|
break;
|
|
case 4:
|
|
cp1 = rtWidget.BottomRight();
|
|
cp2 = rtWidget.BottomLeft();
|
|
vx = -1, vy = -1;
|
|
nx = 1, ny = 0;
|
|
if (bRound) {
|
|
sx = bInverted ? FX_PI * 3 / 2 : 0;
|
|
} else {
|
|
sx = -1, sy = 0;
|
|
}
|
|
break;
|
|
case 6:
|
|
cp1 = rtWidget.BottomLeft();
|
|
cp2 = rtWidget.TopLeft();
|
|
vx = 1, vy = -1;
|
|
nx = 0, ny = 1;
|
|
if (bRound) {
|
|
sx = bInverted ? 0 : FX_PI / 2;
|
|
} else {
|
|
sx = 0;
|
|
sy = -1;
|
|
}
|
|
break;
|
|
}
|
|
if (i == 0)
|
|
fillPath->MoveTo(CFX_PointF(cp1.x, cp1.y + fRadius1));
|
|
|
|
if (bRound) {
|
|
if (fRadius1 < 0)
|
|
sx -= FX_PI;
|
|
if (bInverted)
|
|
sy *= -1;
|
|
|
|
CFX_RectF rtRadius(cp1.x, cp1.y, fRadius1 * 2 * vx, fRadius1 * 2 * vy);
|
|
rtRadius.Normalize();
|
|
if (bInverted)
|
|
rtRadius.Offset(-fRadius1 * vx, -fRadius1 * vy);
|
|
|
|
fillPath->ArcTo(rtRadius.TopLeft(), rtRadius.Size(), sx, sy);
|
|
} else {
|
|
CFX_PointF cp;
|
|
if (bInverted) {
|
|
cp.x = cp1.x + fRadius1 * vx;
|
|
cp.y = cp1.y + fRadius1 * vy;
|
|
} else {
|
|
cp = cp1;
|
|
}
|
|
fillPath->LineTo(cp);
|
|
fillPath->LineTo(
|
|
CFX_PointF(cp1.x + fRadius1 * sx, cp1.y + fRadius1 * sy));
|
|
}
|
|
fillPath->LineTo(CFX_PointF(cp2.x + fRadius2 * nx, cp2.y + fRadius2 * ny));
|
|
}
|
|
}
|
|
|
|
void CXFA_Rectangle::Draw(const std::vector<CXFA_Stroke*>& strokes,
|
|
CXFA_Graphics* pGS,
|
|
CFX_RectF rtWidget,
|
|
const CFX_Matrix& matrix) {
|
|
bool bVisible = false;
|
|
for (int32_t j = 0; j < 4; j++) {
|
|
if (strokes[j * 2 + 1]->IsVisible()) {
|
|
bVisible = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bVisible)
|
|
return;
|
|
|
|
for (int32_t i = 1; i < 8; i += 2) {
|
|
float fThickness = std::fmax(0.0, strokes[i]->GetThickness());
|
|
float fHalf = fThickness / 2;
|
|
XFA_AttributeValue iHand = GetHand();
|
|
switch (i) {
|
|
case 1:
|
|
if (iHand == XFA_AttributeValue::Left) {
|
|
rtWidget.top -= fHalf;
|
|
rtWidget.height += fHalf;
|
|
} else if (iHand == XFA_AttributeValue::Right) {
|
|
rtWidget.top += fHalf;
|
|
rtWidget.height -= fHalf;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (iHand == XFA_AttributeValue::Left) {
|
|
rtWidget.width += fHalf;
|
|
} else if (iHand == XFA_AttributeValue::Right) {
|
|
rtWidget.width -= fHalf;
|
|
}
|
|
break;
|
|
case 5:
|
|
if (iHand == XFA_AttributeValue::Left) {
|
|
rtWidget.height += fHalf;
|
|
} else if (iHand == XFA_AttributeValue::Right) {
|
|
rtWidget.height -= fHalf;
|
|
}
|
|
break;
|
|
case 7:
|
|
if (iHand == XFA_AttributeValue::Left) {
|
|
rtWidget.left -= fHalf;
|
|
rtWidget.width += fHalf;
|
|
} else if (iHand == XFA_AttributeValue::Right) {
|
|
rtWidget.left += fHalf;
|
|
rtWidget.width -= fHalf;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
Stroke(strokes, pGS, rtWidget, matrix);
|
|
}
|
|
|
|
void CXFA_Rectangle::Stroke(const std::vector<CXFA_Stroke*>& strokes,
|
|
CXFA_Graphics* pGS,
|
|
CFX_RectF rtWidget,
|
|
const CFX_Matrix& matrix) {
|
|
bool bVisible;
|
|
float fThickness;
|
|
XFA_AttributeValue i3DType;
|
|
std::tie(i3DType, bVisible, fThickness) = Get3DStyle();
|
|
if (i3DType != XFA_AttributeValue::Unknown) {
|
|
if (!bVisible || fThickness < 0.001f)
|
|
return;
|
|
|
|
switch (i3DType) {
|
|
case XFA_AttributeValue::Lowered:
|
|
StrokeLowered(pGS, rtWidget, fThickness, matrix);
|
|
break;
|
|
case XFA_AttributeValue::Raised:
|
|
StrokeRaised(pGS, rtWidget, fThickness, matrix);
|
|
break;
|
|
case XFA_AttributeValue::Etched:
|
|
StrokeEtched(pGS, rtWidget, fThickness, matrix);
|
|
break;
|
|
case XFA_AttributeValue::Embossed:
|
|
StrokeEmbossed(pGS, rtWidget, fThickness, matrix);
|
|
break;
|
|
default:
|
|
NOTREACHED();
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
bool bClose = false;
|
|
bool bSameStyles = true;
|
|
CXFA_Stroke* stroke1 = strokes[0];
|
|
for (int32_t i = 1; i < 8; i++) {
|
|
CXFA_Stroke* stroke2 = strokes[i];
|
|
if (!stroke1->SameStyles(stroke2, 0)) {
|
|
bSameStyles = false;
|
|
break;
|
|
}
|
|
stroke1 = stroke2;
|
|
}
|
|
if (bSameStyles) {
|
|
stroke1 = strokes[0];
|
|
bClose = true;
|
|
for (int32_t i = 2; i < 8; i += 2) {
|
|
CXFA_Stroke* stroke2 = strokes[i];
|
|
if (!stroke1->SameStyles(stroke2, XFA_STROKE_SAMESTYLE_NoPresence |
|
|
XFA_STROKE_SAMESTYLE_Corner)) {
|
|
bSameStyles = false;
|
|
break;
|
|
}
|
|
stroke1 = stroke2;
|
|
}
|
|
if (bSameStyles) {
|
|
stroke1 = strokes[0];
|
|
if (stroke1->IsInverted())
|
|
bSameStyles = false;
|
|
if (stroke1->GetJoinType() != XFA_AttributeValue::Square)
|
|
bSameStyles = false;
|
|
}
|
|
}
|
|
|
|
bool bStart = true;
|
|
CXFA_GEPath path;
|
|
for (int32_t i = 0; i < 8; i++) {
|
|
CXFA_Stroke* stroke = strokes[i];
|
|
if ((i % 1) == 0 && stroke->GetRadius() < 0) {
|
|
bool bEmpty = path.IsEmpty();
|
|
if (!bEmpty) {
|
|
if (stroke)
|
|
stroke->Stroke(&path, pGS, matrix);
|
|
path.Clear();
|
|
}
|
|
bStart = true;
|
|
continue;
|
|
}
|
|
GetPath(strokes, rtWidget, path, i, bStart, !bSameStyles);
|
|
|
|
bStart = !stroke->SameStyles(strokes[(i + 1) % 8], 0);
|
|
if (bStart) {
|
|
if (stroke)
|
|
stroke->Stroke(&path, pGS, matrix);
|
|
path.Clear();
|
|
}
|
|
}
|
|
bool bEmpty = path.IsEmpty();
|
|
if (!bEmpty) {
|
|
if (bClose) {
|
|
path.Close();
|
|
}
|
|
if (strokes[7])
|
|
strokes[7]->Stroke(&path, pGS, matrix);
|
|
}
|
|
}
|
|
|
|
void CXFA_Rectangle::StrokeRect(CXFA_Graphics* pGraphic,
|
|
const CFX_RectF& rt,
|
|
float fLineWidth,
|
|
const CFX_Matrix& matrix,
|
|
FX_ARGB argbTopLeft,
|
|
FX_ARGB argbBottomRight) {
|
|
float fBottom = rt.bottom();
|
|
float fRight = rt.right();
|
|
CXFA_GEPath pathLT;
|
|
pathLT.MoveTo(CFX_PointF(rt.left, fBottom));
|
|
pathLT.LineTo(CFX_PointF(rt.left, rt.top));
|
|
pathLT.LineTo(CFX_PointF(fRight, rt.top));
|
|
pathLT.LineTo(CFX_PointF(fRight - fLineWidth, rt.top + fLineWidth));
|
|
pathLT.LineTo(CFX_PointF(rt.left + fLineWidth, rt.top + fLineWidth));
|
|
pathLT.LineTo(CFX_PointF(rt.left + fLineWidth, fBottom - fLineWidth));
|
|
pathLT.LineTo(CFX_PointF(rt.left, fBottom));
|
|
pGraphic->SetFillColor(CXFA_GEColor(argbTopLeft));
|
|
pGraphic->FillPath(&pathLT, FXFILL_WINDING, &matrix);
|
|
|
|
CXFA_GEPath pathRB;
|
|
pathRB.MoveTo(CFX_PointF(fRight, rt.top));
|
|
pathRB.LineTo(CFX_PointF(fRight, fBottom));
|
|
pathRB.LineTo(CFX_PointF(rt.left, fBottom));
|
|
pathRB.LineTo(CFX_PointF(rt.left + fLineWidth, fBottom - fLineWidth));
|
|
pathRB.LineTo(CFX_PointF(fRight - fLineWidth, fBottom - fLineWidth));
|
|
pathRB.LineTo(CFX_PointF(fRight - fLineWidth, rt.top + fLineWidth));
|
|
pathRB.LineTo(CFX_PointF(fRight, rt.top));
|
|
pGraphic->SetFillColor(CXFA_GEColor(argbBottomRight));
|
|
pGraphic->FillPath(&pathRB, FXFILL_WINDING, &matrix);
|
|
}
|
|
|
|
void CXFA_Rectangle::StrokeLowered(CXFA_Graphics* pGS,
|
|
CFX_RectF rt,
|
|
float fThickness,
|
|
const CFX_Matrix& matrix) {
|
|
float fHalfWidth = fThickness / 2.0f;
|
|
CFX_RectF rtInner(rt);
|
|
rtInner.Deflate(fHalfWidth, fHalfWidth);
|
|
|
|
CXFA_GEPath path;
|
|
path.AddRectangle(rt.left, rt.top, rt.width, rt.height);
|
|
path.AddRectangle(rtInner.left, rtInner.top, rtInner.width, rtInner.height);
|
|
pGS->SetFillColor(CXFA_GEColor(0xFF000000));
|
|
pGS->FillPath(&path, FXFILL_ALTERNATE, &matrix);
|
|
|
|
StrokeRect(pGS, rtInner, fHalfWidth, matrix, 0xFF808080, 0xFFC0C0C0);
|
|
}
|
|
|
|
void CXFA_Rectangle::StrokeRaised(CXFA_Graphics* pGS,
|
|
CFX_RectF rt,
|
|
float fThickness,
|
|
const CFX_Matrix& matrix) {
|
|
float fHalfWidth = fThickness / 2.0f;
|
|
CFX_RectF rtInner(rt);
|
|
rtInner.Deflate(fHalfWidth, fHalfWidth);
|
|
|
|
CXFA_GEPath path;
|
|
path.AddRectangle(rt.left, rt.top, rt.width, rt.height);
|
|
path.AddRectangle(rtInner.left, rtInner.top, rtInner.width, rtInner.height);
|
|
pGS->SetFillColor(CXFA_GEColor(0xFF000000));
|
|
pGS->FillPath(&path, FXFILL_ALTERNATE, &matrix);
|
|
|
|
StrokeRect(pGS, rtInner, fHalfWidth, matrix, 0xFFFFFFFF, 0xFF808080);
|
|
}
|
|
|
|
void CXFA_Rectangle::StrokeEtched(CXFA_Graphics* pGS,
|
|
CFX_RectF rt,
|
|
float fThickness,
|
|
const CFX_Matrix& matrix) {
|
|
float fHalfWidth = fThickness / 2.0f;
|
|
StrokeRect(pGS, rt, fThickness, matrix, 0xFF808080, 0xFFFFFFFF);
|
|
|
|
CFX_RectF rtInner(rt);
|
|
rtInner.Deflate(fHalfWidth, fHalfWidth);
|
|
StrokeRect(pGS, rtInner, fHalfWidth, matrix, 0xFFFFFFFF, 0xFF808080);
|
|
}
|
|
|
|
void CXFA_Rectangle::StrokeEmbossed(CXFA_Graphics* pGS,
|
|
CFX_RectF rt,
|
|
float fThickness,
|
|
const CFX_Matrix& matrix) {
|
|
float fHalfWidth = fThickness / 2.0f;
|
|
StrokeRect(pGS, rt, fThickness, matrix, 0xFF808080, 0xFF000000);
|
|
|
|
CFX_RectF rtInner(rt);
|
|
rtInner.Deflate(fHalfWidth, fHalfWidth);
|
|
StrokeRect(pGS, rtInner, fHalfWidth, matrix, 0xFF000000, 0xFF808080);
|
|
}
|
|
|
|
void CXFA_Rectangle::GetPath(const std::vector<CXFA_Stroke*>& strokes,
|
|
CFX_RectF rtWidget,
|
|
CXFA_GEPath& path,
|
|
int32_t nIndex,
|
|
bool bStart,
|
|
bool bCorner) {
|
|
ASSERT(nIndex >= 0);
|
|
ASSERT(nIndex < 8);
|
|
|
|
int32_t n = (nIndex & 1) ? nIndex - 1 : nIndex;
|
|
CXFA_Stroke* corner1 = strokes[n];
|
|
CXFA_Stroke* corner2 = strokes[(n + 2) % 8];
|
|
float fRadius1 = bCorner ? corner1->GetRadius() : 0.0f;
|
|
float fRadius2 = bCorner ? corner2->GetRadius() : 0.0f;
|
|
bool bInverted = corner1->IsInverted();
|
|
float offsetY = 0.0f;
|
|
float offsetX = 0.0f;
|
|
bool bRound = corner1->GetJoinType() == XFA_AttributeValue::Round;
|
|
float halfAfter = 0.0f;
|
|
float halfBefore = 0.0f;
|
|
|
|
CXFA_Stroke* stroke = strokes[nIndex];
|
|
if (stroke->IsCorner()) {
|
|
CXFA_Stroke* strokeBefore = strokes[(nIndex + 1 * 8 - 1) % 8];
|
|
CXFA_Stroke* strokeAfter = strokes[nIndex + 1];
|
|
if (stroke->IsInverted()) {
|
|
if (!stroke->SameStyles(strokeBefore, 0))
|
|
halfBefore = strokeBefore->GetThickness() / 2;
|
|
if (!stroke->SameStyles(strokeAfter, 0))
|
|
halfAfter = strokeAfter->GetThickness() / 2;
|
|
}
|
|
} else {
|
|
CXFA_Stroke* strokeBefore = strokes[(nIndex + 8 - 2) % 8];
|
|
CXFA_Stroke* strokeAfter = strokes[(nIndex + 2) % 8];
|
|
if (!bRound && !bInverted) {
|
|
halfBefore = strokeBefore->GetThickness() / 2;
|
|
halfAfter = strokeAfter->GetThickness() / 2;
|
|
}
|
|
}
|
|
|
|
float offsetEX = 0.0f;
|
|
float offsetEY = 0.0f;
|
|
float sx = 0.0f;
|
|
float sy = 0.0f;
|
|
float vx = 1.0f;
|
|
float vy = 1.0f;
|
|
float nx = 1.0f;
|
|
float ny = 1.0f;
|
|
CFX_PointF cpStart;
|
|
CFX_PointF cp1;
|
|
CFX_PointF cp2;
|
|
if (bRound)
|
|
sy = FX_PI / 2;
|
|
|
|
switch (nIndex) {
|
|
case 0:
|
|
case 1:
|
|
cp1 = rtWidget.TopLeft();
|
|
cp2 = rtWidget.TopRight();
|
|
if (nIndex == 0) {
|
|
cpStart.x = cp1.x - halfBefore;
|
|
cpStart.y = cp1.y + fRadius1, offsetY = -halfAfter;
|
|
} else {
|
|
cpStart.x = cp1.x + fRadius1 - halfBefore, cpStart.y = cp1.y,
|
|
offsetEX = halfAfter;
|
|
}
|
|
vx = 1, vy = 1;
|
|
nx = -1, ny = 0;
|
|
if (bRound) {
|
|
sx = bInverted ? FX_PI / 2 : FX_PI;
|
|
} else {
|
|
sx = 1, sy = 0;
|
|
}
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
cp1 = rtWidget.TopRight();
|
|
cp2 = rtWidget.BottomRight();
|
|
if (nIndex == 2) {
|
|
cpStart.x = cp1.x - fRadius1, cpStart.y = cp1.y - halfBefore,
|
|
offsetX = halfAfter;
|
|
} else {
|
|
cpStart.x = cp1.x, cpStart.y = cp1.y + fRadius1 - halfBefore,
|
|
offsetEY = halfAfter;
|
|
}
|
|
vx = -1, vy = 1;
|
|
nx = 0, ny = -1;
|
|
if (bRound) {
|
|
sx = bInverted ? FX_PI : FX_PI * 3 / 2;
|
|
} else {
|
|
sx = 0, sy = 1;
|
|
}
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
cp1 = rtWidget.BottomRight();
|
|
cp2 = rtWidget.BottomLeft();
|
|
if (nIndex == 4) {
|
|
cpStart.x = cp1.x + halfBefore, cpStart.y = cp1.y - fRadius1,
|
|
offsetY = halfAfter;
|
|
} else {
|
|
cpStart.x = cp1.x - fRadius1 + halfBefore, cpStart.y = cp1.y,
|
|
offsetEX = -halfAfter;
|
|
}
|
|
vx = -1, vy = -1;
|
|
nx = 1, ny = 0;
|
|
if (bRound) {
|
|
sx = bInverted ? FX_PI * 3 / 2 : 0;
|
|
} else {
|
|
sx = -1, sy = 0;
|
|
}
|
|
break;
|
|
case 6:
|
|
case 7:
|
|
cp1 = rtWidget.BottomLeft();
|
|
cp2 = rtWidget.TopLeft();
|
|
if (nIndex == 6) {
|
|
cpStart.x = cp1.x + fRadius1, cpStart.y = cp1.y + halfBefore,
|
|
offsetX = -halfAfter;
|
|
} else {
|
|
cpStart.x = cp1.x, cpStart.y = cp1.y - fRadius1 + halfBefore,
|
|
offsetEY = -halfAfter;
|
|
}
|
|
vx = 1;
|
|
vy = -1;
|
|
nx = 0;
|
|
ny = 1;
|
|
if (bRound) {
|
|
sx = bInverted ? 0 : FX_PI / 2;
|
|
} else {
|
|
sx = 0;
|
|
sy = -1;
|
|
}
|
|
break;
|
|
}
|
|
if (bStart) {
|
|
path.MoveTo(cpStart);
|
|
}
|
|
if (nIndex & 1) {
|
|
path.LineTo(CFX_PointF(cp2.x + fRadius2 * nx + offsetEX,
|
|
cp2.y + fRadius2 * ny + offsetEY));
|
|
return;
|
|
}
|
|
if (bRound) {
|
|
if (fRadius1 < 0)
|
|
sx -= FX_PI;
|
|
if (bInverted)
|
|
sy *= -1;
|
|
|
|
CFX_RectF rtRadius(cp1.x + offsetX * 2, cp1.y + offsetY * 2,
|
|
fRadius1 * 2 * vx - offsetX * 2,
|
|
fRadius1 * 2 * vy - offsetY * 2);
|
|
rtRadius.Normalize();
|
|
if (bInverted)
|
|
rtRadius.Offset(-fRadius1 * vx, -fRadius1 * vy);
|
|
|
|
path.ArcTo(rtRadius.TopLeft(), rtRadius.Size(), sx, sy);
|
|
} else {
|
|
CFX_PointF cp;
|
|
if (bInverted) {
|
|
cp.x = cp1.x + fRadius1 * vx;
|
|
cp.y = cp1.y + fRadius1 * vy;
|
|
} else {
|
|
cp = cp1;
|
|
}
|
|
path.LineTo(cp);
|
|
path.LineTo(CFX_PointF(cp1.x + fRadius1 * sx + offsetX,
|
|
cp1.y + fRadius1 * sy + offsetY));
|
|
}
|
|
}
|