From aca769671c706607ff29882c46bac77baa449acb Mon Sep 17 00:00:00 2001 From: Dan Sinclair Date: Wed, 17 Jan 2018 18:40:41 +0000 Subject: Move rectangle drawing code to CXFA_Rectangle This CL moves code related to drawing rectangles to the CXFA_Rectangle class. This also turns CXFA_Border into a CXFA_Rectangle to share the drawing code. Change-Id: I91e2e73b33ecbcda477cf953cf7609310a01fcd4 Reviewed-on: https://pdfium-review.googlesource.com/23110 Reviewed-by: Ryan Harrison Commit-Queue: Ryan Harrison Commit-Queue: dsinclair --- xfa/fxfa/parser/cxfa_rectangle.cpp | 435 +++++++++++++++++++++++++++++++++++++ 1 file changed, 435 insertions(+) (limited to 'xfa/fxfa/parser/cxfa_rectangle.cpp') diff --git a/xfa/fxfa/parser/cxfa_rectangle.cpp b/xfa/fxfa/parser/cxfa_rectangle.cpp index 01a204d149..861cf443a7 100644 --- a/xfa/fxfa/parser/cxfa_rectangle.cpp +++ b/xfa/fxfa/parser/cxfa_rectangle.cpp @@ -6,8 +6,12 @@ #include "xfa/fxfa/parser/cxfa_rectangle.h" +#include + #include "fxjs/xfa/cjx_rectangle.h" #include "third_party/base/ptr_util.h" +#include "xfa/fxfa/parser/cxfa_corner.h" +#include "xfa/fxfa/parser/cxfa_stroke.h" namespace { @@ -38,4 +42,435 @@ CXFA_Rectangle::CXFA_Rectangle(CXFA_Document* doc, XFA_PacketType packet) kName, pdfium::MakeUnique(this)) {} +CXFA_Rectangle::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 js_node) + : CXFA_Box(pDoc, + ePacket, + validPackets, + oType, + eType, + properties, + attributes, + elementName, + std::move(js_node)) {} + CXFA_Rectangle::~CXFA_Rectangle() {} + +void CXFA_Rectangle::Draw(const std::vector& 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_AttributeEnum iHand = GetHand(); + switch (i) { + case 1: + if (iHand == XFA_AttributeEnum::Left) { + rtWidget.top -= fHalf; + rtWidget.height += fHalf; + } else if (iHand == XFA_AttributeEnum::Right) { + rtWidget.top += fHalf; + rtWidget.height -= fHalf; + } + break; + case 3: + if (iHand == XFA_AttributeEnum::Left) { + rtWidget.width += fHalf; + } else if (iHand == XFA_AttributeEnum::Right) { + rtWidget.width -= fHalf; + } + break; + case 5: + if (iHand == XFA_AttributeEnum::Left) { + rtWidget.height += fHalf; + } else if (iHand == XFA_AttributeEnum::Right) { + rtWidget.height -= fHalf; + } + break; + case 7: + if (iHand == XFA_AttributeEnum::Left) { + rtWidget.left -= fHalf; + rtWidget.width += fHalf; + } else if (iHand == XFA_AttributeEnum::Right) { + rtWidget.left += fHalf; + rtWidget.width -= fHalf; + } + break; + } + } + Stroke(strokes, pGS, rtWidget, matrix); +} + +void CXFA_Rectangle::Stroke(const std::vector& strokes, + CXFA_Graphics* pGS, + CFX_RectF rtWidget, + const CFX_Matrix& matrix) { + bool bVisible; + float fThickness; + XFA_AttributeEnum i3DType; + std::tie(i3DType, bVisible, fThickness) = Get3DStyle(); + if (i3DType != XFA_AttributeEnum::Unknown) { + if (!bVisible || fThickness < 0.001f) + return; + + switch (i3DType) { + case XFA_AttributeEnum::Lowered: + StrokeLowered(pGS, rtWidget, fThickness, matrix); + break; + case XFA_AttributeEnum::Raised: + StrokeRaised(pGS, rtWidget, fThickness, matrix); + break; + case XFA_AttributeEnum::Etched: + StrokeEtched(pGS, rtWidget, fThickness, matrix); + break; + case XFA_AttributeEnum::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_AttributeEnum::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& strokes, + CFX_RectF rtWidget, + CXFA_GEPath& path, + int32_t nIndex, + bool bStart, + bool bCorner) { + ASSERT(nIndex >= 0 && nIndex < 8); + + int32_t n = (nIndex & 1) ? nIndex - 1 : nIndex; + auto* corner1 = static_cast(strokes[n]); + auto* corner2 = static_cast(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_AttributeEnum::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)); + } +} -- cgit v1.2.3