From 181ffee7dd19906f9eee175627a9e6d0abb2e881 Mon Sep 17 00:00:00 2001 From: Dan Sinclair Date: Wed, 17 Jan 2018 16:23:06 +0000 Subject: Move the box drawing code to CXFA_Box This CL moves the code related to drawing boxes from CXFA_FFWidget to CXFA_Box. Change-Id: Ie69c59bb0b1eda1fcedbc26c6f8f30d53e2e268c Reviewed-on: https://pdfium-review.googlesource.com/23070 Commit-Queue: dsinclair Reviewed-by: Ryan Harrison --- xfa/fxfa/cxfa_ffwidget.cpp | 946 ++----------------------------------------- xfa/fxfa/parser/cxfa_box.cpp | 843 ++++++++++++++++++++++++++++++++++++++ xfa/fxfa/parser/cxfa_box.h | 7 + 3 files changed, 883 insertions(+), 913 deletions(-) diff --git a/xfa/fxfa/cxfa_ffwidget.cpp b/xfa/fxfa/cxfa_ffwidget.cpp index b24b6dacab..4836e04811 100644 --- a/xfa/fxfa/cxfa_ffwidget.cpp +++ b/xfa/fxfa/cxfa_ffwidget.cpp @@ -13,13 +13,11 @@ #include #include "core/fpdfapi/cpdf_modulemgr.h" -#include "core/fpdfapi/page/cpdf_pageobjectholder.h" #include "core/fxcodec/codec/ccodec_progressivedecoder.h" #include "core/fxcodec/fx_codec.h" #include "core/fxcrt/cfx_memorystream.h" #include "core/fxcrt/maybe_owned.h" #include "core/fxge/cfx_pathdata.h" -#include "core/fxge/dib/cfx_imagerenderer.h" #include "xfa/fwl/fwl_widgethit.h" #include "xfa/fxfa/cxfa_eventparam.h" #include "xfa/fxfa/cxfa_ffapp.h" @@ -27,921 +25,17 @@ #include "xfa/fxfa/cxfa_ffdocview.h" #include "xfa/fxfa/cxfa_ffpageview.h" #include "xfa/fxfa/cxfa_imagerenderer.h" -#include "xfa/fxfa/cxfa_textlayout.h" #include "xfa/fxfa/cxfa_widgetacc.h" #include "xfa/fxfa/parser/cxfa_border.h" #include "xfa/fxfa/parser/cxfa_box.h" -#include "xfa/fxfa/parser/cxfa_corner.h" -#include "xfa/fxfa/parser/cxfa_edge.h" -#include "xfa/fxfa/parser/cxfa_fill.h" #include "xfa/fxfa/parser/cxfa_image.h" #include "xfa/fxfa/parser/cxfa_layoutprocessor.h" #include "xfa/fxfa/parser/cxfa_margin.h" #include "xfa/fxfa/parser/cxfa_node.h" -#include "xfa/fxgraphics/cxfa_gecolor.h" -#include "xfa/fxgraphics/cxfa_gepath.h" -#include "xfa/fxgraphics/cxfa_gepattern.h" -#include "xfa/fxgraphics/cxfa_geshading.h" #include "xfa/fxgraphics/cxfa_graphics.h" namespace { -void XFA_BOX_GetPath_Arc(CXFA_Box* box, - CFX_RectF rtDraw, - CXFA_GEPath& fillPath, - bool forceRound) { - float a, b; - a = rtDraw.width / 2.0f; - b = rtDraw.height / 2.0f; - if (box->IsCircular() || forceRound) - a = b = std::min(a, b); - - CFX_PointF center = rtDraw.Center(); - rtDraw.left = center.x - a; - rtDraw.top = center.y - b; - rtDraw.width = a + a; - rtDraw.height = b + b; - Optional startAngle = box->GetStartAngle(); - Optional sweepAngle = box->GetSweepAngle(); - if (!startAngle && !sweepAngle) { - fillPath.AddEllipse(rtDraw); - return; - } - - fillPath.AddArc(rtDraw.TopLeft(), rtDraw.Size(), - -startAngle.value_or(0) * FX_PI / 180.0f, - -sweepAngle.value_or(360) * FX_PI / 180.0f); -} - -void XFA_BOX_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)); - } -} - -void XFA_BOX_GetFillPath(CXFA_Box* box, - const std::vector& strokes, - CFX_RectF rtWidget, - CXFA_GEPath& fillPath, - bool forceRound) { - if (box->IsArc() || forceRound) { - CXFA_Edge* edge = box->GetEdgeIfExists(0); - float fThickness = std::fmax(0.0, edge ? edge->GetThickness() : 0); - float fHalf = fThickness / 2; - XFA_AttributeEnum iHand = box->GetHand(); - if (iHand == XFA_AttributeEnum::Left) - rtWidget.Inflate(fHalf, fHalf); - else if (iHand == XFA_AttributeEnum::Right) - rtWidget.Deflate(fHalf, fHalf); - - XFA_BOX_GetPath_Arc(box, rtWidget, fillPath, forceRound); - return; - } - - 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_AttributeEnum::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; - auto* corner1 = static_cast(strokes[i]); - auto* corner2 = static_cast(strokes[(i + 2) % 8]); - float fRadius1 = corner1->GetRadius(); - float fRadius2 = corner2->GetRadius(); - bool bInverted = corner1->IsInverted(); - bool bRound = corner1->GetJoinType() == XFA_AttributeEnum::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 XFA_BOX_Fill_Radial(CXFA_Fill* fill, - CXFA_Graphics* pGS, - CXFA_GEPath& fillPath, - CFX_RectF rtFill, - const CFX_Matrix& matrix) { - ASSERT(fill); - - FX_ARGB crStart = fill->GetColor(false); - FX_ARGB crEnd = fill->GetRadialColor(); - if (!fill->IsRadialToEdge()) - std::swap(crStart, crEnd); - - CXFA_GEShading shading(rtFill.Center(), rtFill.Center(), 0, - sqrt(rtFill.Width() * rtFill.Width() + - rtFill.Height() * rtFill.Height()) / - 2, - true, true, crStart, crEnd); - pGS->SetFillColor(CXFA_GEColor(&shading)); - pGS->FillPath(&fillPath, FXFILL_WINDING, &matrix); -} - -void XFA_BOX_Fill_Pattern(CXFA_Fill* fill, - CXFA_Graphics* pGS, - CXFA_GEPath& fillPath, - CFX_RectF rtFill, - const CFX_Matrix& matrix) { - ASSERT(fill); - - FX_ARGB crStart = fill->GetColor(false); - FX_ARGB crEnd = fill->GetPatternColor(); - FX_HatchStyle iHatch = FX_HatchStyle::Cross; - switch (fill->GetPatternType()) { - case XFA_AttributeEnum::CrossDiagonal: - iHatch = FX_HatchStyle::DiagonalCross; - break; - case XFA_AttributeEnum::DiagonalLeft: - iHatch = FX_HatchStyle::ForwardDiagonal; - break; - case XFA_AttributeEnum::DiagonalRight: - iHatch = FX_HatchStyle::BackwardDiagonal; - break; - case XFA_AttributeEnum::Horizontal: - iHatch = FX_HatchStyle::Horizontal; - break; - case XFA_AttributeEnum::Vertical: - iHatch = FX_HatchStyle::Vertical; - break; - default: - break; - } - - CXFA_GEPattern pattern(iHatch, crEnd, crStart); - pGS->SetFillColor(CXFA_GEColor(&pattern, 0x0)); - pGS->FillPath(&fillPath, FXFILL_WINDING, &matrix); -} - -void XFA_BOX_Fill_Linear(CXFA_Fill* fill, - CXFA_Graphics* pGS, - CXFA_GEPath& fillPath, - CFX_RectF rtFill, - const CFX_Matrix& matrix) { - ASSERT(fill); - - FX_ARGB crStart = fill->GetColor(false); - FX_ARGB crEnd = fill->GetLinearColor(); - - CFX_PointF ptStart; - CFX_PointF ptEnd; - switch (fill->GetLinearType()) { - case XFA_AttributeEnum::ToRight: - ptStart = CFX_PointF(rtFill.left, rtFill.top); - ptEnd = CFX_PointF(rtFill.right(), rtFill.top); - break; - case XFA_AttributeEnum::ToBottom: - ptStart = CFX_PointF(rtFill.left, rtFill.top); - ptEnd = CFX_PointF(rtFill.left, rtFill.bottom()); - break; - case XFA_AttributeEnum::ToLeft: - ptStart = CFX_PointF(rtFill.right(), rtFill.top); - ptEnd = CFX_PointF(rtFill.left, rtFill.top); - break; - case XFA_AttributeEnum::ToTop: - ptStart = CFX_PointF(rtFill.left, rtFill.bottom()); - ptEnd = CFX_PointF(rtFill.left, rtFill.top); - break; - default: - break; - } - - CXFA_GEShading shading(ptStart, ptEnd, false, false, crStart, crEnd); - pGS->SetFillColor(CXFA_GEColor(&shading)); - pGS->FillPath(&fillPath, FXFILL_WINDING, &matrix); -} - -void XFA_BOX_Fill(CXFA_Box* box, - const std::vector& strokes, - CXFA_Graphics* pGS, - const CFX_RectF& rtWidget, - const CFX_Matrix& matrix, - bool forceRound) { - CXFA_Fill* fill = box->GetFillIfExists(); - if (!fill || !fill->IsVisible()) - return; - - pGS->SaveGraphState(); - CXFA_GEPath fillPath; - XFA_BOX_GetFillPath(box, strokes, rtWidget, fillPath, forceRound); - fillPath.Close(); - XFA_Element eType = fill->GetFillType(); - switch (eType) { - case XFA_Element::Radial: - XFA_BOX_Fill_Radial(fill, pGS, fillPath, rtWidget, matrix); - break; - case XFA_Element::Pattern: - XFA_BOX_Fill_Pattern(fill, pGS, fillPath, rtWidget, matrix); - break; - case XFA_Element::Linear: - XFA_BOX_Fill_Linear(fill, pGS, fillPath, rtWidget, matrix); - break; - default: { - FX_ARGB cr; - if (eType == XFA_Element::Stipple) { - int32_t iRate = fill->GetStippleRate(); - if (iRate == 0) - iRate = 100; - - int32_t a; - FX_COLORREF rgb; - std::tie(a, rgb) = ArgbToColorRef(fill->GetStippleColor()); - cr = ArgbEncode(iRate * a / 100, rgb); - } else { - cr = fill->GetColor(false); - } - pGS->SetFillColor(CXFA_GEColor(cr)); - pGS->FillPath(&fillPath, FXFILL_WINDING, &matrix); - } break; - } - pGS->RestoreGraphState(); -} - -void XFA_BOX_StrokeArc(CXFA_Box* box, - CXFA_Graphics* pGS, - CFX_RectF rtWidget, - const CFX_Matrix& matrix, - bool forceRound) { - CXFA_Edge* edge = box->GetEdgeIfExists(0); - if (!edge || !edge->IsVisible()) - return; - - bool bVisible; - float fThickness; - XFA_AttributeEnum i3DType; - std::tie(i3DType, bVisible, fThickness) = box->Get3DStyle(); - bool lowered3d = false; - if (i3DType != XFA_AttributeEnum::Unknown) { - if (bVisible && fThickness >= 0.001f) - lowered3d = true; - } - - float fHalf = edge->GetThickness() / 2; - if (fHalf < 0) { - fHalf = 0; - } - - XFA_AttributeEnum iHand = box->GetHand(); - if (iHand == XFA_AttributeEnum::Left) { - rtWidget.Inflate(fHalf, fHalf); - } else if (iHand == XFA_AttributeEnum::Right) { - rtWidget.Deflate(fHalf, fHalf); - } - if (!forceRound || !lowered3d) { - if (fHalf < 0.001f) - return; - - CXFA_GEPath arcPath; - XFA_BOX_GetPath_Arc(box, rtWidget, arcPath, forceRound); - if (edge) - edge->Stroke(&arcPath, pGS, matrix); - return; - } - pGS->SaveGraphState(); - pGS->SetLineWidth(fHalf); - - float a, b; - a = rtWidget.width / 2.0f; - b = rtWidget.height / 2.0f; - if (forceRound) { - a = std::min(a, b); - b = a; - } - - CFX_PointF center = rtWidget.Center(); - rtWidget.left = center.x - a; - rtWidget.top = center.y - b; - rtWidget.width = a + a; - rtWidget.height = b + b; - - float startAngle = 0, sweepAngle = 360; - startAngle = startAngle * FX_PI / 180.0f; - sweepAngle = -sweepAngle * FX_PI / 180.0f; - - CXFA_GEPath arcPath; - arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FX_PI / 4.0f, - FX_PI); - - pGS->SetStrokeColor(CXFA_GEColor(0xFF808080)); - pGS->StrokePath(&arcPath, &matrix); - arcPath.Clear(); - arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), -1.0f * FX_PI / 4.0f, - FX_PI); - - pGS->SetStrokeColor(CXFA_GEColor(0xFFFFFFFF)); - pGS->StrokePath(&arcPath, &matrix); - rtWidget.Deflate(fHalf, fHalf); - arcPath.Clear(); - arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FX_PI / 4.0f, - FX_PI); - - pGS->SetStrokeColor(CXFA_GEColor(0xFF404040)); - pGS->StrokePath(&arcPath, &matrix); - arcPath.Clear(); - arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), -1.0f * FX_PI / 4.0f, - FX_PI); - - pGS->SetStrokeColor(CXFA_GEColor(0xFFC0C0C0)); - pGS->StrokePath(&arcPath, &matrix); - pGS->RestoreGraphState(); -} - -void XFA_Draw3DRect(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 XFA_BOX_Stroke_3DRect_Lowered(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); - XFA_Draw3DRect(pGS, rtInner, fHalfWidth, matrix, 0xFF808080, 0xFFC0C0C0); -} - -void XFA_BOX_Stroke_3DRect_Raised(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); - XFA_Draw3DRect(pGS, rtInner, fHalfWidth, matrix, 0xFFFFFFFF, 0xFF808080); -} - -void XFA_BOX_Stroke_3DRect_Etched(CXFA_Graphics* pGS, - CFX_RectF rt, - float fThickness, - const CFX_Matrix& matrix) { - float fHalfWidth = fThickness / 2.0f; - XFA_Draw3DRect(pGS, rt, fThickness, matrix, 0xFF808080, 0xFFFFFFFF); - CFX_RectF rtInner(rt); - rtInner.Deflate(fHalfWidth, fHalfWidth); - XFA_Draw3DRect(pGS, rtInner, fHalfWidth, matrix, 0xFFFFFFFF, 0xFF808080); -} - -void XFA_BOX_Stroke_3DRect_Embossed(CXFA_Graphics* pGS, - CFX_RectF rt, - float fThickness, - const CFX_Matrix& matrix) { - float fHalfWidth = fThickness / 2.0f; - XFA_Draw3DRect(pGS, rt, fThickness, matrix, 0xFF808080, 0xFF000000); - CFX_RectF rtInner(rt); - rtInner.Deflate(fHalfWidth, fHalfWidth); - XFA_Draw3DRect(pGS, rtInner, fHalfWidth, matrix, 0xFF000000, 0xFF808080); -} - -void XFA_BOX_Stroke_Rect(CXFA_Box* box, - 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) = box->Get3DStyle(); - if (i3DType != XFA_AttributeEnum::Unknown) { - if (!bVisible || fThickness < 0.001f) { - return; - } - switch (i3DType) { - case XFA_AttributeEnum::Lowered: - XFA_BOX_Stroke_3DRect_Lowered(pGS, rtWidget, fThickness, matrix); - break; - case XFA_AttributeEnum::Raised: - XFA_BOX_Stroke_3DRect_Raised(pGS, rtWidget, fThickness, matrix); - break; - case XFA_AttributeEnum::Etched: - XFA_BOX_Stroke_3DRect_Etched(pGS, rtWidget, fThickness, matrix); - break; - case XFA_AttributeEnum::Embossed: - XFA_BOX_Stroke_3DRect_Embossed(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; - } - XFA_BOX_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 XFA_BOX_Stroke(CXFA_Box* box, - const std::vector& strokes, - CXFA_Graphics* pGS, - CFX_RectF rtWidget, - const CFX_Matrix& matrix, - bool forceRound) { - if (box->IsArc() || forceRound) { - XFA_BOX_StrokeArc(box, pGS, rtWidget, matrix, forceRound); - return; - } - - 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 = box->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; - } - } - XFA_BOX_Stroke_Rect(box, strokes, pGS, rtWidget, matrix); -} - -void XFA_DrawBox(CXFA_Box* box, - CXFA_Graphics* pGS, - const CFX_RectF& rtWidget, - const CFX_Matrix& matrix, - bool forceRound) { - if (!box || box->GetPresence() != XFA_AttributeEnum::Visible) - return; - - XFA_Element eType = box->GetElementType(); - if (eType != XFA_Element::Arc && eType != XFA_Element::Border && - eType != XFA_Element::Rectangle) { - return; - } - std::vector strokes; - if (!forceRound && eType != XFA_Element::Arc) - strokes = box->GetStrokes(); - - XFA_BOX_Fill(box, strokes, pGS, rtWidget, matrix, forceRound); - XFA_BOX_Stroke(box, strokes, pGS, rtWidget, matrix, forceRound); -} - -void XFA_GetMatrix(CFX_Matrix& m, - int32_t iRotate, - XFA_AttributeEnum at, - const CFX_RectF& rt) { - if (!iRotate) { - return; - } - float fAnchorX = 0; - float fAnchorY = 0; - switch (at) { - case XFA_AttributeEnum::TopLeft: - fAnchorX = rt.left, fAnchorY = rt.top; - break; - case XFA_AttributeEnum::TopCenter: - fAnchorX = (rt.left + rt.right()) / 2, fAnchorY = rt.top; - break; - case XFA_AttributeEnum::TopRight: - fAnchorX = rt.right(), fAnchorY = rt.top; - break; - case XFA_AttributeEnum::MiddleLeft: - fAnchorX = rt.left, fAnchorY = (rt.top + rt.bottom()) / 2; - break; - case XFA_AttributeEnum::MiddleCenter: - fAnchorX = (rt.left + rt.right()) / 2, - fAnchorY = (rt.top + rt.bottom()) / 2; - break; - case XFA_AttributeEnum::MiddleRight: - fAnchorX = rt.right(), fAnchorY = (rt.top + rt.bottom()) / 2; - break; - case XFA_AttributeEnum::BottomLeft: - fAnchorX = rt.left, fAnchorY = rt.bottom(); - break; - case XFA_AttributeEnum::BottomCenter: - fAnchorX = (rt.left + rt.right()) / 2, fAnchorY = rt.bottom(); - break; - case XFA_AttributeEnum::BottomRight: - fAnchorX = rt.right(), fAnchorY = rt.bottom(); - break; - default: - break; - } - switch (iRotate) { - case 90: - m.a = 0, m.b = -1, m.c = 1, m.d = 0, m.e = fAnchorX - fAnchorY, - m.f = fAnchorX + fAnchorY; - break; - case 180: - m.a = -1, m.b = 0, m.c = 0, m.d = -1, m.e = fAnchorX * 2, - m.f = fAnchorY * 2; - break; - case 270: - m.a = 0, m.b = 1, m.c = -1, m.d = 0, m.e = fAnchorX + fAnchorY, - m.f = fAnchorY - fAnchorX; - break; - } -} - FXDIB_Format XFA_GetDIBFormat(FXCODEC_IMAGE_TYPE type, int32_t iComponents, int32_t iBitsPerComponent) { @@ -1291,7 +385,8 @@ void CXFA_FFWidget::DrawBorder(CXFA_Graphics* pGS, CXFA_Box* box, const CFX_RectF& rtBorder, const CFX_Matrix& matrix) { - XFA_DrawBox(box, pGS, rtBorder, matrix, false); + if (box) + box->Draw(pGS, rtBorder, matrix, false); } void CXFA_FFWidget::DrawBorderWithFlag(CXFA_Graphics* pGS, @@ -1299,7 +394,8 @@ void CXFA_FFWidget::DrawBorderWithFlag(CXFA_Graphics* pGS, const CFX_RectF& rtBorder, const CFX_Matrix& matrix, bool forceRound) { - XFA_DrawBox(box, pGS, rtBorder, matrix, forceRound); + if (box) + box->Draw(pGS, rtBorder, matrix, forceRound); } void CXFA_FFWidget::AddInvalidateRect() { @@ -1476,15 +572,38 @@ CFX_PointF CXFA_FFWidget::Rotate2Normal(const CFX_PointF& point) { } CFX_Matrix CXFA_FFWidget::GetRotateMatrix() { - CFX_Matrix mt; int32_t iRotate = m_pNode->GetRotate(); if (!iRotate) - return mt; + return CFX_Matrix(); CFX_RectF rcWidget = GetRectWithoutRotate(); - XFA_AttributeEnum at = XFA_AttributeEnum::TopLeft; - XFA_GetMatrix(mt, iRotate, at, rcWidget); - + CFX_Matrix mt; + switch (iRotate) { + case 90: + mt.a = 0; + mt.b = -1; + mt.c = 1; + mt.d = 0; + mt.e = rcWidget.left - rcWidget.top; + mt.f = rcWidget.left + rcWidget.top; + break; + case 180: + mt.a = -1; + mt.b = 0; + mt.c = 0; + mt.d = -1; + mt.e = rcWidget.left * 2; + mt.f = rcWidget.top * 2; + break; + case 270: + mt.a = 0; + mt.b = 1; + mt.c = -1; + mt.d = 0; + mt.e = rcWidget.left + rcWidget.top; + mt.f = rcWidget.top - rcWidget.left; + break; + } return mt; } @@ -1492,6 +611,7 @@ bool CXFA_FFWidget::IsLayoutRectEmpty() { CFX_RectF rtLayout = GetRectWithoutRotate(); return rtLayout.width < 0.1f && rtLayout.height < 0.1f; } + CXFA_FFWidget* CXFA_FFWidget::GetParent() { CXFA_Node* pParentNode = m_pNode->GetParent(); if (pParentNode) { diff --git a/xfa/fxfa/parser/cxfa_box.cpp b/xfa/fxfa/parser/cxfa_box.cpp index 5f8bed9aa1..38bbc59595 100644 --- a/xfa/fxfa/parser/cxfa_box.cpp +++ b/xfa/fxfa/parser/cxfa_box.cpp @@ -6,6 +6,7 @@ #include "xfa/fxfa/parser/cxfa_box.h" +#include #include #include "xfa/fxfa/parser/cxfa_corner.h" @@ -14,6 +15,10 @@ #include "xfa/fxfa/parser/cxfa_margin.h" #include "xfa/fxfa/parser/cxfa_measurement.h" #include "xfa/fxfa/parser/cxfa_node.h" +#include "xfa/fxgraphics/cxfa_gepath.h" +#include "xfa/fxgraphics/cxfa_gepattern.h" +#include "xfa/fxgraphics/cxfa_geshading.h" +#include "xfa/fxgraphics/cxfa_graphics.h" namespace { @@ -44,6 +49,824 @@ std::pair Style3D( return {XFA_AttributeEnum::Unknown, stroke}; } +void XFA_BOX_GetPath_Arc(CXFA_Box* box, + CFX_RectF rtDraw, + CXFA_GEPath& fillPath, + bool forceRound) { + float a, b; + a = rtDraw.width / 2.0f; + b = rtDraw.height / 2.0f; + if (box->IsCircular() || forceRound) + a = b = std::min(a, b); + + CFX_PointF center = rtDraw.Center(); + rtDraw.left = center.x - a; + rtDraw.top = center.y - b; + rtDraw.width = a + a; + rtDraw.height = b + b; + Optional startAngle = box->GetStartAngle(); + Optional sweepAngle = box->GetSweepAngle(); + if (!startAngle && !sweepAngle) { + fillPath.AddEllipse(rtDraw); + return; + } + + fillPath.AddArc(rtDraw.TopLeft(), rtDraw.Size(), + -startAngle.value_or(0) * FX_PI / 180.0f, + -sweepAngle.value_or(360) * FX_PI / 180.0f); +} + +void XFA_BOX_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)); + } +} + +void XFA_BOX_GetFillPath(CXFA_Box* box, + const std::vector& strokes, + CFX_RectF rtWidget, + CXFA_GEPath& fillPath, + bool forceRound) { + if (box->IsArc() || forceRound) { + CXFA_Edge* edge = box->GetEdgeIfExists(0); + float fThickness = std::fmax(0.0, edge ? edge->GetThickness() : 0); + float fHalf = fThickness / 2; + XFA_AttributeEnum iHand = box->GetHand(); + if (iHand == XFA_AttributeEnum::Left) + rtWidget.Inflate(fHalf, fHalf); + else if (iHand == XFA_AttributeEnum::Right) + rtWidget.Deflate(fHalf, fHalf); + + XFA_BOX_GetPath_Arc(box, rtWidget, fillPath, forceRound); + return; + } + + 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_AttributeEnum::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; + auto* corner1 = static_cast(strokes[i]); + auto* corner2 = static_cast(strokes[(i + 2) % 8]); + float fRadius1 = corner1->GetRadius(); + float fRadius2 = corner2->GetRadius(); + bool bInverted = corner1->IsInverted(); + bool bRound = corner1->GetJoinType() == XFA_AttributeEnum::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 XFA_BOX_Fill_Radial(CXFA_Fill* fill, + CXFA_Graphics* pGS, + CXFA_GEPath& fillPath, + CFX_RectF rtFill, + const CFX_Matrix& matrix) { + ASSERT(fill); + + FX_ARGB crStart = fill->GetColor(false); + FX_ARGB crEnd = fill->GetRadialColor(); + if (!fill->IsRadialToEdge()) + std::swap(crStart, crEnd); + + CXFA_GEShading shading(rtFill.Center(), rtFill.Center(), 0, + sqrt(rtFill.Width() * rtFill.Width() + + rtFill.Height() * rtFill.Height()) / + 2, + true, true, crStart, crEnd); + pGS->SetFillColor(CXFA_GEColor(&shading)); + pGS->FillPath(&fillPath, FXFILL_WINDING, &matrix); +} + +void XFA_BOX_Fill_Pattern(CXFA_Fill* fill, + CXFA_Graphics* pGS, + CXFA_GEPath& fillPath, + CFX_RectF rtFill, + const CFX_Matrix& matrix) { + ASSERT(fill); + + FX_ARGB crStart = fill->GetColor(false); + FX_ARGB crEnd = fill->GetPatternColor(); + FX_HatchStyle iHatch = FX_HatchStyle::Cross; + switch (fill->GetPatternType()) { + case XFA_AttributeEnum::CrossDiagonal: + iHatch = FX_HatchStyle::DiagonalCross; + break; + case XFA_AttributeEnum::DiagonalLeft: + iHatch = FX_HatchStyle::ForwardDiagonal; + break; + case XFA_AttributeEnum::DiagonalRight: + iHatch = FX_HatchStyle::BackwardDiagonal; + break; + case XFA_AttributeEnum::Horizontal: + iHatch = FX_HatchStyle::Horizontal; + break; + case XFA_AttributeEnum::Vertical: + iHatch = FX_HatchStyle::Vertical; + break; + default: + break; + } + + CXFA_GEPattern pattern(iHatch, crEnd, crStart); + pGS->SetFillColor(CXFA_GEColor(&pattern, 0x0)); + pGS->FillPath(&fillPath, FXFILL_WINDING, &matrix); +} + +void XFA_BOX_Fill_Linear(CXFA_Fill* fill, + CXFA_Graphics* pGS, + CXFA_GEPath& fillPath, + CFX_RectF rtFill, + const CFX_Matrix& matrix) { + ASSERT(fill); + + FX_ARGB crStart = fill->GetColor(false); + FX_ARGB crEnd = fill->GetLinearColor(); + + CFX_PointF ptStart; + CFX_PointF ptEnd; + switch (fill->GetLinearType()) { + case XFA_AttributeEnum::ToRight: + ptStart = CFX_PointF(rtFill.left, rtFill.top); + ptEnd = CFX_PointF(rtFill.right(), rtFill.top); + break; + case XFA_AttributeEnum::ToBottom: + ptStart = CFX_PointF(rtFill.left, rtFill.top); + ptEnd = CFX_PointF(rtFill.left, rtFill.bottom()); + break; + case XFA_AttributeEnum::ToLeft: + ptStart = CFX_PointF(rtFill.right(), rtFill.top); + ptEnd = CFX_PointF(rtFill.left, rtFill.top); + break; + case XFA_AttributeEnum::ToTop: + ptStart = CFX_PointF(rtFill.left, rtFill.bottom()); + ptEnd = CFX_PointF(rtFill.left, rtFill.top); + break; + default: + break; + } + + CXFA_GEShading shading(ptStart, ptEnd, false, false, crStart, crEnd); + pGS->SetFillColor(CXFA_GEColor(&shading)); + pGS->FillPath(&fillPath, FXFILL_WINDING, &matrix); +} + +void XFA_BOX_Fill(CXFA_Box* box, + const std::vector& strokes, + CXFA_Graphics* pGS, + const CFX_RectF& rtWidget, + const CFX_Matrix& matrix, + bool forceRound) { + CXFA_Fill* fill = box->GetFillIfExists(); + if (!fill || !fill->IsVisible()) + return; + + pGS->SaveGraphState(); + CXFA_GEPath fillPath; + XFA_BOX_GetFillPath(box, strokes, rtWidget, fillPath, forceRound); + fillPath.Close(); + XFA_Element eType = fill->GetFillType(); + switch (eType) { + case XFA_Element::Radial: + XFA_BOX_Fill_Radial(fill, pGS, fillPath, rtWidget, matrix); + break; + case XFA_Element::Pattern: + XFA_BOX_Fill_Pattern(fill, pGS, fillPath, rtWidget, matrix); + break; + case XFA_Element::Linear: + XFA_BOX_Fill_Linear(fill, pGS, fillPath, rtWidget, matrix); + break; + default: { + FX_ARGB cr; + if (eType == XFA_Element::Stipple) { + int32_t iRate = fill->GetStippleRate(); + if (iRate == 0) + iRate = 100; + + int32_t a; + FX_COLORREF rgb; + std::tie(a, rgb) = ArgbToColorRef(fill->GetStippleColor()); + cr = ArgbEncode(iRate * a / 100, rgb); + } else { + cr = fill->GetColor(false); + } + pGS->SetFillColor(CXFA_GEColor(cr)); + pGS->FillPath(&fillPath, FXFILL_WINDING, &matrix); + } break; + } + pGS->RestoreGraphState(); +} + +void XFA_BOX_StrokeArc(CXFA_Box* box, + CXFA_Graphics* pGS, + CFX_RectF rtWidget, + const CFX_Matrix& matrix, + bool forceRound) { + CXFA_Edge* edge = box->GetEdgeIfExists(0); + if (!edge || !edge->IsVisible()) + return; + + bool bVisible; + float fThickness; + XFA_AttributeEnum i3DType; + std::tie(i3DType, bVisible, fThickness) = box->Get3DStyle(); + bool lowered3d = false; + if (i3DType != XFA_AttributeEnum::Unknown) { + if (bVisible && fThickness >= 0.001f) + lowered3d = true; + } + + float fHalf = edge->GetThickness() / 2; + if (fHalf < 0) { + fHalf = 0; + } + + XFA_AttributeEnum iHand = box->GetHand(); + if (iHand == XFA_AttributeEnum::Left) { + rtWidget.Inflate(fHalf, fHalf); + } else if (iHand == XFA_AttributeEnum::Right) { + rtWidget.Deflate(fHalf, fHalf); + } + if (!forceRound || !lowered3d) { + if (fHalf < 0.001f) + return; + + CXFA_GEPath arcPath; + XFA_BOX_GetPath_Arc(box, rtWidget, arcPath, forceRound); + if (edge) + edge->Stroke(&arcPath, pGS, matrix); + return; + } + pGS->SaveGraphState(); + pGS->SetLineWidth(fHalf); + + float a, b; + a = rtWidget.width / 2.0f; + b = rtWidget.height / 2.0f; + if (forceRound) { + a = std::min(a, b); + b = a; + } + + CFX_PointF center = rtWidget.Center(); + rtWidget.left = center.x - a; + rtWidget.top = center.y - b; + rtWidget.width = a + a; + rtWidget.height = b + b; + + float startAngle = 0, sweepAngle = 360; + startAngle = startAngle * FX_PI / 180.0f; + sweepAngle = -sweepAngle * FX_PI / 180.0f; + + CXFA_GEPath arcPath; + arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FX_PI / 4.0f, + FX_PI); + + pGS->SetStrokeColor(CXFA_GEColor(0xFF808080)); + pGS->StrokePath(&arcPath, &matrix); + arcPath.Clear(); + arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), -1.0f * FX_PI / 4.0f, + FX_PI); + + pGS->SetStrokeColor(CXFA_GEColor(0xFFFFFFFF)); + pGS->StrokePath(&arcPath, &matrix); + rtWidget.Deflate(fHalf, fHalf); + arcPath.Clear(); + arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FX_PI / 4.0f, + FX_PI); + + pGS->SetStrokeColor(CXFA_GEColor(0xFF404040)); + pGS->StrokePath(&arcPath, &matrix); + arcPath.Clear(); + arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), -1.0f * FX_PI / 4.0f, + FX_PI); + + pGS->SetStrokeColor(CXFA_GEColor(0xFFC0C0C0)); + pGS->StrokePath(&arcPath, &matrix); + pGS->RestoreGraphState(); +} + +void XFA_Draw3DRect(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 XFA_BOX_Stroke_3DRect_Lowered(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); + XFA_Draw3DRect(pGS, rtInner, fHalfWidth, matrix, 0xFF808080, 0xFFC0C0C0); +} + +void XFA_BOX_Stroke_3DRect_Raised(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); + XFA_Draw3DRect(pGS, rtInner, fHalfWidth, matrix, 0xFFFFFFFF, 0xFF808080); +} + +void XFA_BOX_Stroke_3DRect_Etched(CXFA_Graphics* pGS, + CFX_RectF rt, + float fThickness, + const CFX_Matrix& matrix) { + float fHalfWidth = fThickness / 2.0f; + XFA_Draw3DRect(pGS, rt, fThickness, matrix, 0xFF808080, 0xFFFFFFFF); + CFX_RectF rtInner(rt); + rtInner.Deflate(fHalfWidth, fHalfWidth); + XFA_Draw3DRect(pGS, rtInner, fHalfWidth, matrix, 0xFFFFFFFF, 0xFF808080); +} + +void XFA_BOX_Stroke_3DRect_Embossed(CXFA_Graphics* pGS, + CFX_RectF rt, + float fThickness, + const CFX_Matrix& matrix) { + float fHalfWidth = fThickness / 2.0f; + XFA_Draw3DRect(pGS, rt, fThickness, matrix, 0xFF808080, 0xFF000000); + CFX_RectF rtInner(rt); + rtInner.Deflate(fHalfWidth, fHalfWidth); + XFA_Draw3DRect(pGS, rtInner, fHalfWidth, matrix, 0xFF000000, 0xFF808080); +} + +void XFA_BOX_Stroke_Rect(CXFA_Box* box, + 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) = box->Get3DStyle(); + if (i3DType != XFA_AttributeEnum::Unknown) { + if (!bVisible || fThickness < 0.001f) { + return; + } + switch (i3DType) { + case XFA_AttributeEnum::Lowered: + XFA_BOX_Stroke_3DRect_Lowered(pGS, rtWidget, fThickness, matrix); + break; + case XFA_AttributeEnum::Raised: + XFA_BOX_Stroke_3DRect_Raised(pGS, rtWidget, fThickness, matrix); + break; + case XFA_AttributeEnum::Etched: + XFA_BOX_Stroke_3DRect_Etched(pGS, rtWidget, fThickness, matrix); + break; + case XFA_AttributeEnum::Embossed: + XFA_BOX_Stroke_3DRect_Embossed(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; + } + XFA_BOX_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 XFA_BOX_Stroke(CXFA_Box* box, + const std::vector& strokes, + CXFA_Graphics* pGS, + CFX_RectF rtWidget, + const CFX_Matrix& matrix, + bool forceRound) { + if (box->IsArc() || forceRound) { + XFA_BOX_StrokeArc(box, pGS, rtWidget, matrix, forceRound); + return; + } + + 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 = box->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; + } + } + XFA_BOX_Stroke_Rect(box, strokes, pGS, rtWidget, matrix); +} + } // namespace CXFA_Box::CXFA_Box(CXFA_Document* pDoc, @@ -176,3 +999,23 @@ std::vector CXFA_Box::GetStrokesInternal(bool bNull) { } return strokes; } + +void CXFA_Box::Draw(CXFA_Graphics* pGS, + const CFX_RectF& rtWidget, + const CFX_Matrix& matrix, + bool forceRound) { + if (GetPresence() != XFA_AttributeEnum::Visible) + return; + + XFA_Element eType = GetElementType(); + if (eType != XFA_Element::Arc && eType != XFA_Element::Border && + eType != XFA_Element::Rectangle) { + return; + } + std::vector strokes; + if (!forceRound && eType != XFA_Element::Arc) + strokes = GetStrokes(); + + XFA_BOX_Fill(this, strokes, pGS, rtWidget, matrix, forceRound); + XFA_BOX_Stroke(this, strokes, pGS, rtWidget, matrix, forceRound); +} diff --git a/xfa/fxfa/parser/cxfa_box.h b/xfa/fxfa/parser/cxfa_box.h index 216a981c83..215925fe7c 100644 --- a/xfa/fxfa/parser/cxfa_box.h +++ b/xfa/fxfa/parser/cxfa_box.h @@ -11,10 +11,12 @@ #include #include +#include "core/fxcrt/fx_coordinates.h" #include "xfa/fxfa/parser/cxfa_node.h" class CXFA_Edge; class CXFA_Fill; +class CXFA_Graphics; class CXFA_Margin; class CXFA_Stroke; @@ -40,6 +42,11 @@ class CXFA_Box : public CXFA_Node { Optional GetStartAngle(); Optional GetSweepAngle(); + void Draw(CXFA_Graphics* pGS, + const CFX_RectF& rtWidget, + const CFX_Matrix& matrix, + bool forceRound); + protected: CXFA_Box(CXFA_Document* pDoc, XFA_PacketType ePacket, -- cgit v1.2.3