// Copyright 2017 The PDFium Authors
// 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/cxfa_ffline.h"

#include "third_party/base/notreached.h"
#include "xfa/fgas/graphics/cfgas_gecolor.h"
#include "xfa/fgas/graphics/cfgas_gegraphics.h"
#include "xfa/fgas/graphics/cfgas_gepath.h"
#include "xfa/fxfa/parser/cxfa_edge.h"
#include "xfa/fxfa/parser/cxfa_line.h"
#include "xfa/fxfa/parser/cxfa_value.h"

namespace {

CFX_GraphStateData::LineCap LineCapToFXGE(XFA_AttributeValue iLineCap) {
  switch (iLineCap) {
    case XFA_AttributeValue::Round:
      return CFX_GraphStateData::LineCap::kRound;
    case XFA_AttributeValue::Butt:
      return CFX_GraphStateData::LineCap::kButt;
    default:
      return CFX_GraphStateData::LineCap::kSquare;
  }
}

}  // namespace

CXFA_FFLine::CXFA_FFLine(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}

CXFA_FFLine::~CXFA_FFLine() = default;

void CXFA_FFLine::GetRectFromHand(CFX_RectF& rect,
                                  XFA_AttributeValue iHand,
                                  float fLineWidth) {
  float fHalfWidth = fLineWidth / 2.0f;
  if (rect.height < 1.0f) {
    switch (iHand) {
      case XFA_AttributeValue::Left:
        rect.top -= fHalfWidth;
        break;
      case XFA_AttributeValue::Right:
        rect.top += fHalfWidth;
        break;
      case XFA_AttributeValue::Even:
        break;
      default:
        NOTREACHED_NORETURN();
    }
  } else if (rect.width < 1.0f) {
    switch (iHand) {
      case XFA_AttributeValue::Left:
        rect.left += fHalfWidth;
        break;
      case XFA_AttributeValue::Right:
        rect.left += fHalfWidth;
        break;
      case XFA_AttributeValue::Even:
        break;
      default:
        NOTREACHED_NORETURN();
    }
  } else {
    switch (iHand) {
      case XFA_AttributeValue::Left:
        rect.Inflate(fHalfWidth, fHalfWidth);
        break;
      case XFA_AttributeValue::Right:
        rect.Deflate(fHalfWidth, fHalfWidth);
        break;
      case XFA_AttributeValue::Even:
        break;
      default:
        NOTREACHED_NORETURN();
    }
  }
}

void CXFA_FFLine::RenderWidget(CFGAS_GEGraphics* pGS,
                               const CFX_Matrix& matrix,
                               HighlightOption highlight) {
  if (!HasVisibleStatus())
    return;

  CXFA_Value* value = m_pNode->GetFormValueIfExists();
  if (!value)
    return;

  FX_ARGB lineColor = 0xFF000000;
  float fLineWidth = 1.0f;
  XFA_AttributeValue iStrokeType = XFA_AttributeValue::Unknown;
  XFA_AttributeValue iCap = XFA_AttributeValue::Unknown;
  CXFA_Line* line = value->GetLineIfExists();
  if (line) {
    CXFA_Edge* edge = line->GetEdgeIfExists();
    if (edge && !edge->IsVisible())
      return;

    if (edge) {
      lineColor = edge->GetColor();
      iStrokeType = edge->GetStrokeType();
      fLineWidth = edge->GetThickness();
      iCap = edge->GetCapType();
    }
  }

  CFX_Matrix mtRotate = GetRotateMatrix();
  mtRotate.Concat(matrix);

  CFX_RectF rtLine = GetRectWithoutRotate();
  CXFA_Margin* margin = m_pNode->GetMarginIfExists();
  XFA_RectWithoutMargin(&rtLine, margin);

  GetRectFromHand(rtLine, line ? line->GetHand() : XFA_AttributeValue::Left,
                  fLineWidth);
  CFGAS_GEPath linePath;
  if (line && line->GetSlope() && rtLine.right() > 0.0f &&
      rtLine.bottom() > 0.0f) {
    linePath.AddLine(rtLine.TopRight(), rtLine.BottomLeft());
  } else {
    linePath.AddLine(rtLine.TopLeft(), rtLine.BottomRight());
  }

  CFGAS_GEGraphics::StateRestorer restorer(pGS);
  pGS->SetLineWidth(fLineWidth);
  pGS->EnableActOnDash();
  XFA_StrokeTypeSetLineDash(pGS, iStrokeType, iCap);

  pGS->SetStrokeColor(CFGAS_GEColor(lineColor));
  pGS->SetLineCap(LineCapToFXGE(iCap));
  pGS->StrokePath(linePath, mtRotate);
}
