diff options
Diffstat (limited to 'fpdfsdk/pdfwindow/cpwl_appstream.cpp')
-rw-r--r-- | fpdfsdk/pdfwindow/cpwl_appstream.cpp | 1558 |
1 files changed, 1558 insertions, 0 deletions
diff --git a/fpdfsdk/pdfwindow/cpwl_appstream.cpp b/fpdfsdk/pdfwindow/cpwl_appstream.cpp new file mode 100644 index 0000000000..2b158cdfd0 --- /dev/null +++ b/fpdfsdk/pdfwindow/cpwl_appstream.cpp @@ -0,0 +1,1558 @@ +// 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 "fpdfsdk/pdfwindow/cpwl_appstream.h" + +#include <utility> + +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_name.h" +#include "core/fpdfapi/parser/cpdf_number.h" +#include "core/fpdfapi/parser/cpdf_reference.h" +#include "core/fpdfapi/parser/cpdf_stream.h" +#include "core/fpdfapi/parser/cpdf_string.h" +#include "fpdfsdk/cpdfsdk_formfillenvironment.h" +#include "fpdfsdk/cpdfsdk_interform.h" +#include "fpdfsdk/cpdfsdk_pageview.h" +#include "fpdfsdk/cpdfsdk_widget.h" +#include "fpdfsdk/formfiller/cba_fontmap.h" +#include "fpdfsdk/fxedit/fxet_edit.h" +#include "fpdfsdk/pdfwindow/cpwl_edit.h" +#include "fpdfsdk/pdfwindow/cpwl_icon.h" +#include "fpdfsdk/pdfwindow/cpwl_utils.h" +#include "fpdfsdk/pdfwindow/cpwl_wnd.h" + +namespace { + +CFX_ByteString GetAP_Check(const CFX_FloatRect& crBBox) { + const float fWidth = crBBox.right - crBBox.left; + const float fHeight = crBBox.top - crBBox.bottom; + + CFX_PointF pts[8][3] = {{CFX_PointF(0.28f, 0.52f), CFX_PointF(0.27f, 0.48f), + CFX_PointF(0.29f, 0.40f)}, + {CFX_PointF(0.30f, 0.33f), CFX_PointF(0.31f, 0.29f), + CFX_PointF(0.31f, 0.28f)}, + {CFX_PointF(0.39f, 0.28f), CFX_PointF(0.49f, 0.29f), + CFX_PointF(0.77f, 0.67f)}, + {CFX_PointF(0.76f, 0.68f), CFX_PointF(0.78f, 0.69f), + CFX_PointF(0.76f, 0.75f)}, + {CFX_PointF(0.76f, 0.75f), CFX_PointF(0.73f, 0.80f), + CFX_PointF(0.68f, 0.75f)}, + {CFX_PointF(0.68f, 0.74f), CFX_PointF(0.68f, 0.74f), + CFX_PointF(0.44f, 0.47f)}, + {CFX_PointF(0.43f, 0.47f), CFX_PointF(0.40f, 0.47f), + CFX_PointF(0.41f, 0.58f)}, + {CFX_PointF(0.40f, 0.60f), CFX_PointF(0.28f, 0.66f), + CFX_PointF(0.30f, 0.56f)}}; + + for (size_t i = 0; i < FX_ArraySize(pts); ++i) { + for (size_t j = 0; j < FX_ArraySize(pts[0]); ++j) { + pts[i][j].x = pts[i][j].x * fWidth + crBBox.left; + pts[i][j].y *= pts[i][j].y * fHeight + crBBox.bottom; + } + } + + std::ostringstream csAP; + csAP << pts[0][0].x << " " << pts[0][0].y << " m\n"; + + for (size_t i = 0; i < FX_ArraySize(pts); ++i) { + size_t nNext = i < FX_ArraySize(pts) - 1 ? i + 1 : 0; + + float px1 = pts[i][1].x - pts[i][0].x; + float py1 = pts[i][1].y - pts[i][0].y; + float px2 = pts[i][2].x - pts[nNext][0].x; + float py2 = pts[i][2].y - pts[nNext][0].y; + + csAP << pts[i][0].x + px1 * FX_BEZIER << " " + << pts[i][0].y + py1 * FX_BEZIER << " " + << pts[nNext][0].x + px2 * FX_BEZIER << " " + << pts[nNext][0].y + py2 * FX_BEZIER << " " << pts[nNext][0].x << " " + << pts[nNext][0].y << " c\n"; + } + + return CFX_ByteString(csAP); +} + +CFX_ByteString GetAP_Circle(const CFX_FloatRect& crBBox) { + std::ostringstream csAP; + + float fWidth = crBBox.right - crBBox.left; + float fHeight = crBBox.top - crBBox.bottom; + + CFX_PointF pt1(crBBox.left, crBBox.bottom + fHeight / 2); + CFX_PointF pt2(crBBox.left + fWidth / 2, crBBox.top); + CFX_PointF pt3(crBBox.right, crBBox.bottom + fHeight / 2); + CFX_PointF pt4(crBBox.left + fWidth / 2, crBBox.bottom); + + csAP << pt1.x << " " << pt1.y << " m\n"; + + float px = pt2.x - pt1.x; + float py = pt2.y - pt1.y; + + csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " " + << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y + << " c\n"; + + px = pt3.x - pt2.x; + py = pt2.y - pt3.y; + + csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " " + << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " c\n"; + + px = pt3.x - pt4.x; + py = pt3.y - pt4.y; + + csAP << pt3.x << " " << pt3.y - py * FX_BEZIER << " " + << pt4.x + px * FX_BEZIER << " " << pt4.y << " " << pt4.x << " " << pt4.y + << " c\n"; + + px = pt4.x - pt1.x; + py = pt1.y - pt4.y; + + csAP << pt4.x - px * FX_BEZIER << " " << pt4.y << " " << pt1.x << " " + << pt1.y - py * FX_BEZIER << " " << pt1.x << " " << pt1.y << " c\n"; + + return CFX_ByteString(csAP); +} + +CFX_ByteString GetAP_Cross(const CFX_FloatRect& crBBox) { + std::ostringstream csAP; + + csAP << crBBox.left << " " << crBBox.top << " m\n"; + csAP << crBBox.right << " " << crBBox.bottom << " l\n"; + csAP << crBBox.left << " " << crBBox.bottom << " m\n"; + csAP << crBBox.right << " " << crBBox.top << " l\n"; + + return CFX_ByteString(csAP); +} + +CFX_ByteString GetAP_Diamond(const CFX_FloatRect& crBBox) { + std::ostringstream csAP; + + float fWidth = crBBox.right - crBBox.left; + float fHeight = crBBox.top - crBBox.bottom; + + CFX_PointF pt1(crBBox.left, crBBox.bottom + fHeight / 2); + CFX_PointF pt2(crBBox.left + fWidth / 2, crBBox.top); + CFX_PointF pt3(crBBox.right, crBBox.bottom + fHeight / 2); + CFX_PointF pt4(crBBox.left + fWidth / 2, crBBox.bottom); + + csAP << pt1.x << " " << pt1.y << " m\n"; + csAP << pt2.x << " " << pt2.y << " l\n"; + csAP << pt3.x << " " << pt3.y << " l\n"; + csAP << pt4.x << " " << pt4.y << " l\n"; + csAP << pt1.x << " " << pt1.y << " l\n"; + + return CFX_ByteString(csAP); +} + +CFX_ByteString GetAP_Square(const CFX_FloatRect& crBBox) { + std::ostringstream csAP; + + csAP << crBBox.left << " " << crBBox.top << " m\n"; + csAP << crBBox.right << " " << crBBox.top << " l\n"; + csAP << crBBox.right << " " << crBBox.bottom << " l\n"; + csAP << crBBox.left << " " << crBBox.bottom << " l\n"; + csAP << crBBox.left << " " << crBBox.top << " l\n"; + + return CFX_ByteString(csAP); +} + +CFX_ByteString GetAP_Star(const CFX_FloatRect& crBBox) { + std::ostringstream csAP; + + float fRadius = (crBBox.top - crBBox.bottom) / (1 + (float)cos(FX_PI / 5.0f)); + CFX_PointF ptCenter = CFX_PointF((crBBox.left + crBBox.right) / 2.0f, + (crBBox.top + crBBox.bottom) / 2.0f); + + float px[5]; + float py[5]; + float fAngel = FX_PI / 10.0f; + for (int32_t i = 0; i < 5; i++) { + px[i] = ptCenter.x + fRadius * (float)cos(fAngel); + py[i] = ptCenter.y + fRadius * (float)sin(fAngel); + fAngel += FX_PI * 2 / 5.0f; + } + + csAP << px[0] << " " << py[0] << " m\n"; + + int32_t nNext = 0; + for (int32_t j = 0; j < 5; j++) { + nNext += 2; + if (nNext >= 5) + nNext -= 5; + csAP << px[nNext] << " " << py[nNext] << " l\n"; + } + + return CFX_ByteString(csAP); +} + +CFX_ByteString GetAP_HalfCircle(const CFX_FloatRect& crBBox, float fRotate) { + std::ostringstream csAP; + + float fWidth = crBBox.right - crBBox.left; + float fHeight = crBBox.top - crBBox.bottom; + + CFX_PointF pt1(-fWidth / 2, 0); + CFX_PointF pt2(0, fHeight / 2); + CFX_PointF pt3(fWidth / 2, 0); + + float px; + float py; + + csAP << cos(fRotate) << " " << sin(fRotate) << " " << -sin(fRotate) << " " + << cos(fRotate) << " " << crBBox.left + fWidth / 2 << " " + << crBBox.bottom + fHeight / 2 << " cm\n"; + + csAP << pt1.x << " " << pt1.y << " m\n"; + + px = pt2.x - pt1.x; + py = pt2.y - pt1.y; + + csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " " + << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y + << " c\n"; + + px = pt3.x - pt2.x; + py = pt2.y - pt3.y; + + csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " " + << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " c\n"; + + return CFX_ByteString(csAP); +} + +CFX_ByteString GetAppStream_Check(const CFX_FloatRect& rcBBox, + const CFX_Color& crText) { + std::ostringstream sAP; + sAP << "q\n" + << CPWL_Utils::GetColorAppStream(crText, true) << GetAP_Check(rcBBox) + << "f\nQ\n"; + return CFX_ByteString(sAP); +} + +CFX_ByteString GetAppStream_Circle(const CFX_FloatRect& rcBBox, + const CFX_Color& crText) { + std::ostringstream sAP; + sAP << "q\n" + << CPWL_Utils::GetColorAppStream(crText, true) << GetAP_Circle(rcBBox) + << "f\nQ\n"; + return CFX_ByteString(sAP); +} + +CFX_ByteString GetAppStream_Cross(const CFX_FloatRect& rcBBox, + const CFX_Color& crText) { + std::ostringstream sAP; + sAP << "q\n" + << CPWL_Utils::GetColorAppStream(crText, false) << GetAP_Cross(rcBBox) + << "S\nQ\n"; + return CFX_ByteString(sAP); +} + +CFX_ByteString GetAppStream_Diamond(const CFX_FloatRect& rcBBox, + const CFX_Color& crText) { + std::ostringstream sAP; + sAP << "q\n1 w\n" + << CPWL_Utils::GetColorAppStream(crText, true) << GetAP_Diamond(rcBBox) + << "f\nQ\n"; + return CFX_ByteString(sAP); +} + +CFX_ByteString GetAppStream_Square(const CFX_FloatRect& rcBBox, + const CFX_Color& crText) { + std::ostringstream sAP; + sAP << "q\n" + << CPWL_Utils::GetColorAppStream(crText, true) << GetAP_Square(rcBBox) + << "f\nQ\n"; + return CFX_ByteString(sAP); +} + +CFX_ByteString GetAppStream_Star(const CFX_FloatRect& rcBBox, + const CFX_Color& crText) { + std::ostringstream sAP; + sAP << "q\n" + << CPWL_Utils::GetColorAppStream(crText, true) << GetAP_Star(rcBBox) + << "f\nQ\n"; + return CFX_ByteString(sAP); +} + +CFX_ByteString GetCircleFillAppStream(const CFX_FloatRect& rect, + const CFX_Color& color) { + std::ostringstream sAppStream; + CFX_ByteString sColor = CPWL_Utils::GetColorAppStream(color, true); + if (sColor.GetLength() > 0) + sAppStream << "q\n" << sColor << GetAP_Circle(rect) << "f\nQ\n"; + return CFX_ByteString(sAppStream); +} + +CFX_ByteString GetCircleBorderAppStream(const CFX_FloatRect& rect, + float fWidth, + const CFX_Color& color, + const CFX_Color& crLeftTop, + const CFX_Color& crRightBottom, + BorderStyle nStyle, + const CPWL_Dash& dash) { + std::ostringstream sAppStream; + CFX_ByteString sColor; + + if (fWidth > 0.0f) { + sAppStream << "q\n"; + + float fHalfWidth = fWidth / 2.0f; + CFX_FloatRect rect_by_2 = rect.GetDeflated(fHalfWidth, fHalfWidth); + + float div = fHalfWidth * 0.75f; + CFX_FloatRect rect_by_75 = rect.GetDeflated(div, div); + switch (nStyle) { + default: + case BorderStyle::SOLID: + case BorderStyle::UNDERLINE: { + sColor = CPWL_Utils::GetColorAppStream(color, false); + if (sColor.GetLength() > 0) { + sAppStream << "q\n" + << fWidth << " w\n" + << sColor << GetAP_Circle(rect_by_2) << " S\nQ\n"; + } + } break; + case BorderStyle::DASH: { + sColor = CPWL_Utils::GetColorAppStream(color, false); + if (sColor.GetLength() > 0) { + sAppStream << "q\n" + << fWidth << " w\n" + << "[" << dash.nDash << " " << dash.nGap << "] " + << dash.nPhase << " d\n" + << sColor << GetAP_Circle(rect_by_2) << " S\nQ\n"; + } + } break; + case BorderStyle::BEVELED: { + sColor = CPWL_Utils::GetColorAppStream(color, false); + if (sColor.GetLength() > 0) { + sAppStream << "q\n" + << fHalfWidth << " w\n" + << sColor << GetAP_Circle(rect) << " S\nQ\n"; + } + + sColor = CPWL_Utils::GetColorAppStream(crLeftTop, false); + if (sColor.GetLength() > 0) { + sAppStream << "q\n" + << fHalfWidth << " w\n" + << sColor << GetAP_HalfCircle(rect_by_75, FX_PI / 4.0f) + << " S\nQ\n"; + } + + sColor = CPWL_Utils::GetColorAppStream(crRightBottom, false); + if (sColor.GetLength() > 0) { + sAppStream << "q\n" + << fHalfWidth << " w\n" + << sColor << GetAP_HalfCircle(rect_by_75, FX_PI * 5 / 4.0f) + << " S\nQ\n"; + } + } break; + case BorderStyle::INSET: { + sColor = CPWL_Utils::GetColorAppStream(color, false); + if (sColor.GetLength() > 0) { + sAppStream << "q\n" + << fHalfWidth << " w\n" + << sColor << GetAP_Circle(rect) << " S\nQ\n"; + } + + sColor = CPWL_Utils::GetColorAppStream(crLeftTop, false); + if (sColor.GetLength() > 0) { + sAppStream << "q\n" + << fHalfWidth << " w\n" + << sColor << GetAP_HalfCircle(rect_by_75, FX_PI / 4.0f) + << " S\nQ\n"; + } + + sColor = CPWL_Utils::GetColorAppStream(crRightBottom, false); + if (sColor.GetLength() > 0) { + sAppStream << "q\n" + << fHalfWidth << " w\n" + << sColor << GetAP_HalfCircle(rect_by_75, FX_PI * 5 / 4.0f) + << " S\nQ\n"; + } + } break; + } + + sAppStream << "Q\n"; + } + return CFX_ByteString(sAppStream); +} + +CFX_ByteString GetCheckBoxAppStream(const CFX_FloatRect& rcBBox, + int32_t nStyle, + const CFX_Color& crText) { + CFX_FloatRect rcCenter = rcBBox.GetCenterSquare(); + switch (nStyle) { + default: + case PCS_CHECK: + return GetAppStream_Check(rcCenter, crText); + case PCS_CIRCLE: + rcCenter.Scale(2.0f / 3.0f); + return GetAppStream_Circle(rcCenter, crText); + case PCS_CROSS: + return GetAppStream_Cross(rcCenter, crText); + case PCS_DIAMOND: + rcCenter.Scale(2.0f / 3.0f); + return GetAppStream_Diamond(rcCenter, crText); + case PCS_SQUARE: + rcCenter.Scale(2.0f / 3.0f); + return GetAppStream_Square(rcCenter, crText); + case PCS_STAR: + rcCenter.Scale(2.0f / 3.0f); + return GetAppStream_Star(rcCenter, crText); + } +} + +CFX_ByteString GetRadioButtonAppStream(const CFX_FloatRect& rcBBox, + int32_t nStyle, + const CFX_Color& crText) { + CFX_FloatRect rcCenter = rcBBox.GetCenterSquare(); + switch (nStyle) { + default: + case PCS_CHECK: + return GetAppStream_Check(rcCenter, crText); + case PCS_CIRCLE: + rcCenter.Scale(1.0f / 2.0f); + return GetAppStream_Circle(rcCenter, crText); + case PCS_CROSS: + return GetAppStream_Cross(rcCenter, crText); + case PCS_DIAMOND: + rcCenter.Scale(2.0f / 3.0f); + return GetAppStream_Diamond(rcCenter, crText); + case PCS_SQUARE: + rcCenter.Scale(2.0f / 3.0f); + return GetAppStream_Square(rcCenter, crText); + case PCS_STAR: + rcCenter.Scale(2.0f / 3.0f); + return GetAppStream_Star(rcCenter, crText); + } +} + +CFX_ByteString GetPushButtonAppStream(const CFX_FloatRect& rcBBox, + IPVT_FontMap* pFontMap, + CPDF_Stream* pIconStream, + CPDF_IconFit& IconFit, + const CFX_WideString& sLabel, + const CFX_Color& crText, + float fFontSize, + int32_t nLayOut) { + const float fAutoFontScale = 1.0f / 3.0f; + + auto pEdit = pdfium::MakeUnique<CFX_Edit>(); + pEdit->SetFontMap(pFontMap); + pEdit->SetAlignmentH(1, true); + pEdit->SetAlignmentV(1, true); + pEdit->SetMultiLine(false, true); + pEdit->SetAutoReturn(false, true); + if (IsFloatZero(fFontSize)) + pEdit->SetAutoFontSize(true, true); + else + pEdit->SetFontSize(fFontSize); + + pEdit->Initialize(); + pEdit->SetText(sLabel); + + CFX_FloatRect rcLabelContent = pEdit->GetContentRect(); + CPWL_Icon Icon; + PWL_CREATEPARAM cp; + cp.dwFlags = PWS_VISIBLE; + Icon.Create(cp); + Icon.SetIconFit(&IconFit); + Icon.SetPDFStream(pIconStream); + + CFX_FloatRect rcLabel; + CFX_FloatRect rcIcon; + float fWidth = 0.0f; + float fHeight = 0.0f; + + switch (nLayOut) { + case PPBL_LABEL: + rcLabel = rcBBox; + break; + case PPBL_ICON: + rcIcon = rcBBox; + break; + case PPBL_ICONTOPLABELBOTTOM: + if (pIconStream) { + if (IsFloatZero(fFontSize)) { + fHeight = rcBBox.top - rcBBox.bottom; + rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right, + rcBBox.bottom + fHeight * fAutoFontScale); + rcIcon = + CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right, rcBBox.top); + } else { + fHeight = rcLabelContent.Height(); + + if (rcBBox.bottom + fHeight > rcBBox.top) { + rcLabel = rcBBox; + } else { + rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right, + rcBBox.bottom + fHeight); + rcIcon = CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right, + rcBBox.top); + } + } + } else { + rcLabel = rcBBox; + } + break; + case PPBL_LABELTOPICONBOTTOM: + if (pIconStream) { + if (IsFloatZero(fFontSize)) { + fHeight = rcBBox.top - rcBBox.bottom; + rcLabel = + CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight * fAutoFontScale, + rcBBox.right, rcBBox.top); + rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right, + rcLabel.bottom); + } else { + fHeight = rcLabelContent.Height(); + + if (rcBBox.bottom + fHeight > rcBBox.top) { + rcLabel = rcBBox; + } else { + rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight, + rcBBox.right, rcBBox.top); + rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right, + rcLabel.bottom); + } + } + } else { + rcLabel = rcBBox; + } + break; + case PPBL_ICONLEFTLABELRIGHT: + if (pIconStream) { + if (IsFloatZero(fFontSize)) { + fWidth = rcBBox.right - rcBBox.left; + if (rcLabelContent.Width() < fWidth * fAutoFontScale) { + rcLabel = CFX_FloatRect(rcBBox.right - fWidth * fAutoFontScale, + rcBBox.bottom, rcBBox.right, rcBBox.top); + rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left, + rcBBox.top); + } else { + if (rcLabelContent.Width() < fWidth) { + rcLabel = CFX_FloatRect(rcBBox.right - rcLabelContent.Width(), + rcBBox.bottom, rcBBox.right, rcBBox.top); + rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left, + rcBBox.top); + } else { + rcLabel = rcBBox; + } + } + } else { + fWidth = rcLabelContent.Width(); + if (rcBBox.left + fWidth > rcBBox.right) { + rcLabel = rcBBox; + } else { + rcLabel = CFX_FloatRect(rcBBox.right - fWidth, rcBBox.bottom, + rcBBox.right, rcBBox.top); + rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left, + rcBBox.top); + } + } + } else { + rcLabel = rcBBox; + } + break; + case PPBL_LABELLEFTICONRIGHT: + if (pIconStream) { + if (IsFloatZero(fFontSize)) { + fWidth = rcBBox.right - rcBBox.left; + if (rcLabelContent.Width() < fWidth * fAutoFontScale) { + rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, + rcBBox.left + fWidth * fAutoFontScale, + rcBBox.top); + rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right, + rcBBox.top); + } else { + if (rcLabelContent.Width() < fWidth) { + rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, + rcBBox.left + rcLabelContent.Width(), + rcBBox.top); + rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right, + rcBBox.top); + } else { + rcLabel = rcBBox; + } + } + } else { + fWidth = rcLabelContent.Width(); + if (rcBBox.left + fWidth > rcBBox.right) { + rcLabel = rcBBox; + } else { + rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, + rcBBox.left + fWidth, rcBBox.top); + rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right, + rcBBox.top); + } + } + } else { + rcLabel = rcBBox; + } + break; + case PPBL_LABELOVERICON: + rcLabel = rcBBox; + rcIcon = rcBBox; + break; + } + + std::ostringstream sTemp; + + if (!rcIcon.IsEmpty()) { + Icon.Move(rcIcon, false, false); + sTemp << Icon.GetImageAppStream(); + } + + Icon.Destroy(); + + if (!rcLabel.IsEmpty()) { + pEdit->SetPlateRect(rcLabel); + CFX_ByteString sEdit = + CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, 0.0f)); + if (sEdit.GetLength() > 0) { + sTemp << "BT\n" + << CPWL_Utils::GetColorAppStream(crText) << sEdit << "ET\n"; + } + } + + if (sTemp.tellp() <= 0) + return CFX_ByteString(); + + std::ostringstream sAppStream; + sAppStream << "q\n" + << rcBBox.left << " " << rcBBox.bottom << " " + << rcBBox.right - rcBBox.left << " " << rcBBox.top - rcBBox.bottom + << " re W n\n"; + sAppStream << sTemp.str().c_str() << "Q\n"; + return CFX_ByteString(sAppStream); +} + +CFX_ByteString GetDropButtonAppStream(const CFX_FloatRect& rcBBox) { + if (rcBBox.IsEmpty()) + return CFX_ByteString(); + + std::ostringstream sAppStream; + sAppStream << "q\n" + << CPWL_Utils::GetColorAppStream( + CFX_Color(COLORTYPE_RGB, 220.0f / 255.0f, 220.0f / 255.0f, + 220.0f / 255.0f), + true) + << rcBBox.left << " " << rcBBox.bottom << " " + << rcBBox.right - rcBBox.left << " " << rcBBox.top - rcBBox.bottom + << " re f\n" + << "Q\n"; + + sAppStream << "q\n" + << CPWL_Utils::GetBorderAppStream( + rcBBox, 2, CFX_Color(COLORTYPE_GRAY, 0), + CFX_Color(COLORTYPE_GRAY, 1), + CFX_Color(COLORTYPE_GRAY, 0.5), BorderStyle::BEVELED, + CPWL_Dash(3, 0, 0)) + << "Q\n"; + + CFX_PointF ptCenter = CFX_PointF((rcBBox.left + rcBBox.right) / 2, + (rcBBox.top + rcBBox.bottom) / 2); + if (IsFloatBigger(rcBBox.right - rcBBox.left, 6) && + IsFloatBigger(rcBBox.top - rcBBox.bottom, 6)) { + sAppStream << "q\n" + << " 0 g\n" + << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n" + << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n" + << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n" + << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n" + << "Q\n"; + } + + return CFX_ByteString(sAppStream); +} + +} // namespace + +CPWL_AppStream::CPWL_AppStream(CPDFSDK_Widget* widget, CPDF_Dictionary* dict) + : widget_(widget), dict_(dict) {} + +CPWL_AppStream::~CPWL_AppStream() {} + +void CPWL_AppStream::SetAsPushButton() { + CPDF_FormControl* pControl = widget_->GetFormControl(); + CFX_FloatRect rcWindow = widget_->GetRotatedRect(); + int32_t nLayout = 0; + switch (pControl->GetTextPosition()) { + case TEXTPOS_ICON: + nLayout = PPBL_ICON; + break; + case TEXTPOS_BELOW: + nLayout = PPBL_ICONTOPLABELBOTTOM; + break; + case TEXTPOS_ABOVE: + nLayout = PPBL_LABELTOPICONBOTTOM; + break; + case TEXTPOS_RIGHT: + nLayout = PPBL_ICONLEFTLABELRIGHT; + break; + case TEXTPOS_LEFT: + nLayout = PPBL_LABELLEFTICONRIGHT; + break; + case TEXTPOS_OVERLAID: + nLayout = PPBL_LABELOVERICON; + break; + default: + nLayout = PPBL_LABEL; + break; + } + + CFX_Color crBackground; + CFX_Color crBorder; + int iColorType; + float fc[4]; + pControl->GetOriginalBackgroundColor(iColorType, fc); + if (iColorType > 0) + crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); + + pControl->GetOriginalBorderColor(iColorType, fc); + if (iColorType > 0) + crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); + + float fBorderWidth = static_cast<float>(widget_->GetBorderWidth()); + CPWL_Dash dsBorder(3, 0, 0); + CFX_Color crLeftTop; + CFX_Color crRightBottom; + + BorderStyle nBorderStyle = widget_->GetBorderStyle(); + switch (nBorderStyle) { + case BorderStyle::DASH: + dsBorder = CPWL_Dash(3, 3, 0); + break; + case BorderStyle::BEVELED: + fBorderWidth *= 2; + crLeftTop = CFX_Color(COLORTYPE_GRAY, 1); + crRightBottom = crBackground / 2.0f; + break; + case BorderStyle::INSET: + fBorderWidth *= 2; + crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5); + crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75); + break; + default: + break; + } + + CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth); + CFX_Color crText(COLORTYPE_GRAY, 0); + CFX_ByteString csNameTag; + CPDF_DefaultAppearance da = pControl->GetDefaultAppearance(); + if (da.HasColor()) { + da.GetColor(iColorType, fc); + crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); + } + float fFontSize = 12.0f; + if (da.HasFont()) + csNameTag = da.GetFont(&fFontSize); + + CFX_WideString csWCaption; + CFX_WideString csNormalCaption; + CFX_WideString csRolloverCaption; + CFX_WideString csDownCaption; + if (pControl->HasMKEntry("CA")) + csNormalCaption = pControl->GetNormalCaption(); + + if (pControl->HasMKEntry("RC")) + csRolloverCaption = pControl->GetRolloverCaption(); + + if (pControl->HasMKEntry("AC")) + csDownCaption = pControl->GetDownCaption(); + + CPDF_Stream* pNormalIcon = nullptr; + CPDF_Stream* pRolloverIcon = nullptr; + CPDF_Stream* pDownIcon = nullptr; + if (pControl->HasMKEntry("I")) + pNormalIcon = pControl->GetNormalIcon(); + + if (pControl->HasMKEntry("RI")) + pRolloverIcon = pControl->GetRolloverIcon(); + + if (pControl->HasMKEntry("IX")) + pDownIcon = pControl->GetDownIcon(); + + if (pNormalIcon) { + if (CPDF_Dictionary* pImageDict = pNormalIcon->GetDict()) { + if (pImageDict->GetStringFor("Name").IsEmpty()) + pImageDict->SetNewFor<CPDF_String>("Name", "ImgA", false); + } + } + + if (pRolloverIcon) { + if (CPDF_Dictionary* pImageDict = pRolloverIcon->GetDict()) { + if (pImageDict->GetStringFor("Name").IsEmpty()) + pImageDict->SetNewFor<CPDF_String>("Name", "ImgB", false); + } + } + + if (pDownIcon) { + if (CPDF_Dictionary* pImageDict = pDownIcon->GetDict()) { + if (pImageDict->GetStringFor("Name").IsEmpty()) + pImageDict->SetNewFor<CPDF_String>("Name", "ImgC", false); + } + } + + CPDF_IconFit iconFit = pControl->GetIconFit(); + + CBA_FontMap font_map( + widget_.Get(), + widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler()); + font_map.SetAPType("N"); + + CFX_ByteString csAP = + CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) + + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, + crLeftTop, crRightBottom, nBorderStyle, + dsBorder) + + GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient, + &font_map, pNormalIcon, iconFit, csNormalCaption, + crText, fFontSize, nLayout); + + Write("N", csAP, ""); + if (pNormalIcon) + AddImage("N", pNormalIcon); + + CPDF_FormControl::HighlightingMode eHLM = pControl->GetHighlightingMode(); + if (eHLM == CPDF_FormControl::Push || eHLM == CPDF_FormControl::Toggle) { + if (csRolloverCaption.IsEmpty() && !pRolloverIcon) { + csRolloverCaption = csNormalCaption; + pRolloverIcon = pNormalIcon; + } + + font_map.SetAPType("R"); + + csAP = + CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) + + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, + crLeftTop, crRightBottom, nBorderStyle, + dsBorder) + + GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient, + &font_map, pRolloverIcon, iconFit, + csRolloverCaption, crText, fFontSize, nLayout); + + Write("R", csAP, ""); + if (pRolloverIcon) + AddImage("R", pRolloverIcon); + + if (csDownCaption.IsEmpty() && !pDownIcon) { + csDownCaption = csNormalCaption; + pDownIcon = pNormalIcon; + } + + switch (nBorderStyle) { + case BorderStyle::BEVELED: { + CFX_Color crTemp = crLeftTop; + crLeftTop = crRightBottom; + crRightBottom = crTemp; + break; + } + case BorderStyle::INSET: { + crLeftTop = CFX_Color(COLORTYPE_GRAY, 0); + crRightBottom = CFX_Color(COLORTYPE_GRAY, 1); + break; + } + default: + break; + } + + font_map.SetAPType("D"); + + csAP = CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground - 0.25f) + + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, + crLeftTop, crRightBottom, + nBorderStyle, dsBorder) + + GetPushButtonAppStream( + iconFit.GetFittingBounds() ? rcWindow : rcClient, &font_map, + pDownIcon, iconFit, csDownCaption, crText, fFontSize, nLayout); + + Write("D", csAP, ""); + if (pDownIcon) + AddImage("D", pDownIcon); + } else { + Remove("D"); + Remove("R"); + } +} + +void CPWL_AppStream::SetAsCheckBox() { + CPDF_FormControl* pControl = widget_->GetFormControl(); + CFX_Color crBackground, crBorder, crText; + int iColorType; + float fc[4]; + + pControl->GetOriginalBackgroundColor(iColorType, fc); + if (iColorType > 0) + crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); + + pControl->GetOriginalBorderColor(iColorType, fc); + if (iColorType > 0) + crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); + + float fBorderWidth = static_cast<float>(widget_->GetBorderWidth()); + CPWL_Dash dsBorder(3, 0, 0); + CFX_Color crLeftTop, crRightBottom; + + BorderStyle nBorderStyle = widget_->GetBorderStyle(); + switch (nBorderStyle) { + case BorderStyle::DASH: + dsBorder = CPWL_Dash(3, 3, 0); + break; + case BorderStyle::BEVELED: + fBorderWidth *= 2; + crLeftTop = CFX_Color(COLORTYPE_GRAY, 1); + crRightBottom = crBackground / 2.0f; + break; + case BorderStyle::INSET: + fBorderWidth *= 2; + crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5); + crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75); + break; + default: + break; + } + + CFX_FloatRect rcWindow = widget_->GetRotatedRect(); + CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth); + CPDF_DefaultAppearance da = pControl->GetDefaultAppearance(); + if (da.HasColor()) { + da.GetColor(iColorType, fc); + crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); + } + + int32_t nStyle = 0; + CFX_WideString csWCaption = pControl->GetNormalCaption(); + if (csWCaption.GetLength() > 0) { + switch (csWCaption[0]) { + case L'l': + nStyle = PCS_CIRCLE; + break; + case L'8': + nStyle = PCS_CROSS; + break; + case L'u': + nStyle = PCS_DIAMOND; + break; + case L'n': + nStyle = PCS_SQUARE; + break; + case L'H': + nStyle = PCS_STAR; + break; + default: // L'4' + nStyle = PCS_CHECK; + break; + } + } else { + nStyle = PCS_CHECK; + } + + CFX_ByteString csAP_N_ON = + CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) + + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, + crLeftTop, crRightBottom, nBorderStyle, + dsBorder); + + CFX_ByteString csAP_N_OFF = csAP_N_ON; + + switch (nBorderStyle) { + case BorderStyle::BEVELED: { + CFX_Color crTemp = crLeftTop; + crLeftTop = crRightBottom; + crRightBottom = crTemp; + break; + } + case BorderStyle::INSET: { + crLeftTop = CFX_Color(COLORTYPE_GRAY, 0); + crRightBottom = CFX_Color(COLORTYPE_GRAY, 1); + break; + } + default: + break; + } + + CFX_ByteString csAP_D_ON = + CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground - 0.25f) + + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, + crLeftTop, crRightBottom, nBorderStyle, + dsBorder); + + CFX_ByteString csAP_D_OFF = csAP_D_ON; + + csAP_N_ON += GetCheckBoxAppStream(rcClient, nStyle, crText); + csAP_D_ON += GetCheckBoxAppStream(rcClient, nStyle, crText); + + Write("N", csAP_N_ON, pControl->GetCheckedAPState()); + Write("N", csAP_N_OFF, "Off"); + + Write("D", csAP_D_ON, pControl->GetCheckedAPState()); + Write("D", csAP_D_OFF, "Off"); + + CFX_ByteString csAS = widget_->GetAppState(); + if (csAS.IsEmpty()) + widget_->SetAppState("Off"); +} + +void CPWL_AppStream::SetAsRadioButton() { + CPDF_FormControl* pControl = widget_->GetFormControl(); + CFX_Color crBackground; + CFX_Color crBorder; + CFX_Color crText; + int iColorType; + float fc[4]; + + pControl->GetOriginalBackgroundColor(iColorType, fc); + if (iColorType > 0) + crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); + + pControl->GetOriginalBorderColor(iColorType, fc); + if (iColorType > 0) + crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); + + float fBorderWidth = static_cast<float>(widget_->GetBorderWidth()); + CPWL_Dash dsBorder(3, 0, 0); + CFX_Color crLeftTop; + CFX_Color crRightBottom; + BorderStyle nBorderStyle = widget_->GetBorderStyle(); + switch (nBorderStyle) { + case BorderStyle::DASH: + dsBorder = CPWL_Dash(3, 3, 0); + break; + case BorderStyle::BEVELED: + fBorderWidth *= 2; + crLeftTop = CFX_Color(COLORTYPE_GRAY, 1); + crRightBottom = crBackground / 2.0f; + break; + case BorderStyle::INSET: + fBorderWidth *= 2; + crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5); + crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75); + break; + default: + break; + } + + CFX_FloatRect rcWindow = widget_->GetRotatedRect(); + CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth); + CPDF_DefaultAppearance da = pControl->GetDefaultAppearance(); + if (da.HasColor()) { + da.GetColor(iColorType, fc); + crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); + } + + int32_t nStyle = 0; + CFX_WideString csWCaption = pControl->GetNormalCaption(); + if (csWCaption.GetLength() > 0) { + switch (csWCaption[0]) { + default: // L'l': + nStyle = PCS_CIRCLE; + break; + case L'8': + nStyle = PCS_CROSS; + break; + case L'u': + nStyle = PCS_DIAMOND; + break; + case L'n': + nStyle = PCS_SQUARE; + break; + case L'H': + nStyle = PCS_STAR; + break; + case L'4': + nStyle = PCS_CHECK; + break; + } + } else { + nStyle = PCS_CIRCLE; + } + + CFX_ByteString csAP_N_ON; + CFX_FloatRect rcCenter = rcWindow.GetCenterSquare().GetDeflated(1.0f, 1.0f); + if (nStyle == PCS_CIRCLE) { + if (nBorderStyle == BorderStyle::BEVELED) { + crLeftTop = CFX_Color(COLORTYPE_GRAY, 1); + crRightBottom = crBackground - 0.25f; + } else if (nBorderStyle == BorderStyle::INSET) { + crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5f); + crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75f); + } + + csAP_N_ON = + GetCircleFillAppStream(rcCenter, crBackground) + + GetCircleBorderAppStream(rcCenter, fBorderWidth, crBorder, crLeftTop, + crRightBottom, nBorderStyle, dsBorder); + } else { + csAP_N_ON = CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) + + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, + crLeftTop, crRightBottom, + nBorderStyle, dsBorder); + } + + CFX_ByteString csAP_N_OFF = csAP_N_ON; + + switch (nBorderStyle) { + case BorderStyle::BEVELED: { + CFX_Color crTemp = crLeftTop; + crLeftTop = crRightBottom; + crRightBottom = crTemp; + break; + } + case BorderStyle::INSET: { + crLeftTop = CFX_Color(COLORTYPE_GRAY, 0); + crRightBottom = CFX_Color(COLORTYPE_GRAY, 1); + break; + } + default: + break; + } + + CFX_ByteString csAP_D_ON; + + if (nStyle == PCS_CIRCLE) { + CFX_Color crBK = crBackground - 0.25f; + if (nBorderStyle == BorderStyle::BEVELED) { + crLeftTop = crBackground - 0.25f; + crRightBottom = CFX_Color(COLORTYPE_GRAY, 1); + crBK = crBackground; + } else if (nBorderStyle == BorderStyle::INSET) { + crLeftTop = CFX_Color(COLORTYPE_GRAY, 0); + crRightBottom = CFX_Color(COLORTYPE_GRAY, 1); + } + + csAP_D_ON = + GetCircleFillAppStream(rcCenter, crBK) + + GetCircleBorderAppStream(rcCenter, fBorderWidth, crBorder, crLeftTop, + crRightBottom, nBorderStyle, dsBorder); + } else { + csAP_D_ON = + CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground - 0.25f) + + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, + crLeftTop, crRightBottom, nBorderStyle, + dsBorder); + } + + CFX_ByteString csAP_D_OFF = csAP_D_ON; + + csAP_N_ON += GetRadioButtonAppStream(rcClient, nStyle, crText); + csAP_D_ON += GetRadioButtonAppStream(rcClient, nStyle, crText); + + Write("N", csAP_N_ON, pControl->GetCheckedAPState()); + Write("N", csAP_N_OFF, "Off"); + + Write("D", csAP_D_ON, pControl->GetCheckedAPState()); + Write("D", csAP_D_OFF, "Off"); + + CFX_ByteString csAS = widget_->GetAppState(); + if (csAS.IsEmpty()) + widget_->SetAppState("Off"); +} + +void CPWL_AppStream::SetAsComboBox(const CFX_WideString* sValue) { + CPDF_FormControl* pControl = widget_->GetFormControl(); + CPDF_FormField* pField = pControl->GetField(); + std::ostringstream sBody; + + CFX_FloatRect rcClient = widget_->GetClientRect(); + CFX_FloatRect rcButton = rcClient; + rcButton.left = rcButton.right - 13; + rcButton.Normalize(); + + auto pEdit = pdfium::MakeUnique<CFX_Edit>(); + pEdit->EnableRefresh(false); + + CBA_FontMap font_map( + widget_.Get(), + widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler()); + pEdit->SetFontMap(&font_map); + + CFX_FloatRect rcEdit = rcClient; + rcEdit.right = rcButton.left; + rcEdit.Normalize(); + + pEdit->SetPlateRect(rcEdit); + pEdit->SetAlignmentV(1, true); + + float fFontSize = widget_->GetFontSize(); + if (IsFloatZero(fFontSize)) + pEdit->SetAutoFontSize(true, true); + else + pEdit->SetFontSize(fFontSize); + + pEdit->Initialize(); + + if (sValue) { + pEdit->SetText(*sValue); + } else { + int32_t nCurSel = pField->GetSelectedIndex(0); + if (nCurSel < 0) + pEdit->SetText(pField->GetValue()); + else + pEdit->SetText(pField->GetOptionLabel(nCurSel)); + } + + CFX_FloatRect rcContent = pEdit->GetContentRect(); + CFX_ByteString sEdit = + CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_PointF()); + if (sEdit.GetLength() > 0) { + sBody << "/Tx BMC\n" + << "q\n"; + if (rcContent.Width() > rcEdit.Width() || + rcContent.Height() > rcEdit.Height()) { + sBody << rcEdit.left << " " << rcEdit.bottom << " " << rcEdit.Width() + << " " << rcEdit.Height() << " re\nW\nn\n"; + } + + CFX_Color crText = widget_->GetTextPWLColor(); + sBody << "BT\n" + << CPWL_Utils::GetColorAppStream(crText) << sEdit << "ET\n" + << "Q\nEMC\n"; + } + + sBody << GetDropButtonAppStream(rcButton); + Write("N", + GetBackgroundAppStream() + GetBorderAppStream() + CFX_ByteString(sBody), + ""); +} + +void CPWL_AppStream::SetAsListBox() { + CPDF_FormControl* pControl = widget_->GetFormControl(); + CPDF_FormField* pField = pControl->GetField(); + CFX_FloatRect rcClient = widget_->GetClientRect(); + std::ostringstream sBody; + + auto pEdit = pdfium::MakeUnique<CFX_Edit>(); + pEdit->EnableRefresh(false); + + CBA_FontMap font_map( + widget_.Get(), + widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler()); + pEdit->SetFontMap(&font_map); + pEdit->SetPlateRect(CFX_FloatRect(rcClient.left, 0.0f, rcClient.right, 0.0f)); + + float fFontSize = widget_->GetFontSize(); + pEdit->SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize); + pEdit->Initialize(); + + std::ostringstream sList; + float fy = rcClient.top; + + int32_t nTop = pField->GetTopVisibleIndex(); + int32_t nCount = pField->CountOptions(); + int32_t nSelCount = pField->CountSelectedItems(); + + for (int32_t i = nTop; i < nCount; ++i) { + bool bSelected = false; + for (int32_t j = 0; j < nSelCount; ++j) { + if (pField->GetSelectedIndex(j) == i) { + bSelected = true; + break; + } + } + + pEdit->SetText(pField->GetOptionLabel(i)); + + CFX_FloatRect rcContent = pEdit->GetContentRect(); + float fItemHeight = rcContent.Height(); + + if (bSelected) { + CFX_FloatRect rcItem = + CFX_FloatRect(rcClient.left, fy - fItemHeight, rcClient.right, fy); + sList << "q\n" + << CPWL_Utils::GetColorAppStream( + CFX_Color(COLORTYPE_RGB, 0, 51.0f / 255.0f, 113.0f / 255.0f), + true) + << rcItem.left << " " << rcItem.bottom << " " << rcItem.Width() + << " " << rcItem.Height() << " re f\n" + << "Q\n"; + + sList << "BT\n" + << CPWL_Utils::GetColorAppStream(CFX_Color(COLORTYPE_GRAY, 1), true) + << CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy)) + << "ET\n"; + } else { + CFX_Color crText = widget_->GetTextPWLColor(); + sList << "BT\n" + << CPWL_Utils::GetColorAppStream(crText, true) + << CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy)) + << "ET\n"; + } + + fy -= fItemHeight; + } + + if (sList.tellp() > 0) { + sBody << "/Tx BMC\n" + << "q\n" + << rcClient.left << " " << rcClient.bottom << " " << rcClient.Width() + << " " << rcClient.Height() << " re\nW\nn\n"; + sBody << sList.str() << "Q\nEMC\n"; + } + Write("N", + GetBackgroundAppStream() + GetBorderAppStream() + CFX_ByteString(sBody), + ""); +} + +void CPWL_AppStream::SetAsTextField(const CFX_WideString* sValue) { + CPDF_FormControl* pControl = widget_->GetFormControl(); + CPDF_FormField* pField = pControl->GetField(); + std::ostringstream sBody; + std::ostringstream sLines; + + auto pEdit = pdfium::MakeUnique<CFX_Edit>(); + pEdit->EnableRefresh(false); + + CBA_FontMap font_map( + widget_.Get(), + widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler()); + pEdit->SetFontMap(&font_map); + + CFX_FloatRect rcClient = widget_->GetClientRect(); + pEdit->SetPlateRect(rcClient); + pEdit->SetAlignmentH(pControl->GetControlAlignment(), true); + + uint32_t dwFieldFlags = pField->GetFieldFlags(); + bool bMultiLine = (dwFieldFlags >> 12) & 1; + if (bMultiLine) { + pEdit->SetMultiLine(true, true); + pEdit->SetAutoReturn(true, true); + } else { + pEdit->SetAlignmentV(1, true); + } + + uint16_t subWord = 0; + if ((dwFieldFlags >> 13) & 1) { + subWord = '*'; + pEdit->SetPasswordChar(subWord, true); + } + + int nMaxLen = pField->GetMaxLen(); + bool bCharArray = (dwFieldFlags >> 24) & 1; + float fFontSize = widget_->GetFontSize(); + +#ifdef PDF_ENABLE_XFA + CFX_WideString sValueTmp; + if (!sValue && widget_->GetMixXFAWidget()) { + sValueTmp = widget_->GetValue(true); + sValue = &sValueTmp; + } +#endif // PDF_ENABLE_XFA + + if (nMaxLen > 0) { + if (bCharArray) { + pEdit->SetCharArray(nMaxLen); + + if (IsFloatZero(fFontSize)) { + fFontSize = CPWL_Edit::GetCharArrayAutoFontSize(font_map.GetPDFFont(0), + rcClient, nMaxLen); + } + } else { + if (sValue) + nMaxLen = sValue->GetLength(); + pEdit->SetLimitChar(nMaxLen); + } + } + + if (IsFloatZero(fFontSize)) + pEdit->SetAutoFontSize(true, true); + else + pEdit->SetFontSize(fFontSize); + + pEdit->Initialize(); + pEdit->SetText(sValue ? *sValue : pField->GetValue()); + + CFX_FloatRect rcContent = pEdit->GetContentRect(); + CFX_ByteString sEdit = CPWL_Utils::GetEditAppStream( + pEdit.get(), CFX_PointF(), nullptr, !bCharArray, subWord); + + if (sEdit.GetLength() > 0) { + sBody << "/Tx BMC\n" + << "q\n"; + if (rcContent.Width() > rcClient.Width() || + rcContent.Height() > rcClient.Height()) { + sBody << rcClient.left << " " << rcClient.bottom << " " + << rcClient.Width() << " " << rcClient.Height() << " re\nW\nn\n"; + } + CFX_Color crText = widget_->GetTextPWLColor(); + sBody << "BT\n" + << CPWL_Utils::GetColorAppStream(crText) << sEdit << "ET\n" + << "Q\nEMC\n"; + } + + if (bCharArray) { + switch (widget_->GetBorderStyle()) { + case BorderStyle::SOLID: { + CFX_ByteString sColor = + CPWL_Utils::GetColorAppStream(widget_->GetBorderPWLColor(), false); + if (sColor.GetLength() > 0) { + sLines << "q\n" + << widget_->GetBorderWidth() << " w\n" + << CPWL_Utils::GetColorAppStream(widget_->GetBorderPWLColor(), + false) + << " 2 J 0 j\n"; + + for (int32_t i = 1; i < nMaxLen; ++i) { + sLines << rcClient.left + + ((rcClient.right - rcClient.left) / nMaxLen) * i + << " " << rcClient.bottom << " m\n" + << rcClient.left + + ((rcClient.right - rcClient.left) / nMaxLen) * i + << " " << rcClient.top << " l S\n"; + } + + sLines << "Q\n"; + } + break; + } + case BorderStyle::DASH: { + CFX_ByteString sColor = + CPWL_Utils::GetColorAppStream(widget_->GetBorderPWLColor(), false); + if (sColor.GetLength() > 0) { + CPWL_Dash dsBorder = CPWL_Dash(3, 3, 0); + + sLines << "q\n" + << widget_->GetBorderWidth() << " w\n" + << CPWL_Utils::GetColorAppStream(widget_->GetBorderPWLColor(), + false) + << "[" << dsBorder.nDash << " " << dsBorder.nGap << "] " + << dsBorder.nPhase << " d\n"; + + for (int32_t i = 1; i < nMaxLen; ++i) { + sLines << rcClient.left + + ((rcClient.right - rcClient.left) / nMaxLen) * i + << " " << rcClient.bottom << " m\n" + << rcClient.left + + ((rcClient.right - rcClient.left) / nMaxLen) * i + << " " << rcClient.top << " l S\n"; + } + + sLines << "Q\n"; + } + break; + } + default: + break; + } + } + + Write("N", + GetBackgroundAppStream() + GetBorderAppStream() + + CFX_ByteString(sLines) + CFX_ByteString(sBody), + ""); +} + +void CPWL_AppStream::AddImage(const CFX_ByteString& sAPType, + CPDF_Stream* pImage) { + CPDF_Stream* pStream = dict_->GetStreamFor(sAPType); + CPDF_Dictionary* pStreamDict = pStream->GetDict(); + CFX_ByteString sImageAlias = "IMG"; + + if (CPDF_Dictionary* pImageDict = pImage->GetDict()) { + sImageAlias = pImageDict->GetStringFor("Name"); + if (sImageAlias.IsEmpty()) + sImageAlias = "IMG"; + } + + CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources"); + if (!pStreamResList) + pStreamResList = pStreamDict->SetNewFor<CPDF_Dictionary>("Resources"); + + CPDF_Dictionary* pXObject = + pStreamResList->SetNewFor<CPDF_Dictionary>("XObject"); + pXObject->SetNewFor<CPDF_Reference>(sImageAlias, + widget_->GetPageView()->GetPDFDocument(), + pImage->GetObjNum()); +} + +void CPWL_AppStream::Write(const CFX_ByteString& sAPType, + const CFX_ByteString& sContents, + const CFX_ByteString& sAPState) { + CPDF_Stream* pStream = nullptr; + CPDF_Dictionary* pParentDict = nullptr; + if (sAPState.IsEmpty()) { + pParentDict = dict_.Get(); + pStream = dict_->GetStreamFor(sAPType); + } else { + CPDF_Dictionary* pAPTypeDict = dict_->GetDictFor(sAPType); + if (!pAPTypeDict) + pAPTypeDict = dict_->SetNewFor<CPDF_Dictionary>(sAPType); + + pParentDict = pAPTypeDict; + pStream = pAPTypeDict->GetStreamFor(sAPState); + } + + if (!pStream) { + CPDF_Document* doc = widget_->GetPageView()->GetPDFDocument(); + pStream = doc->NewIndirect<CPDF_Stream>(); + pParentDict->SetNewFor<CPDF_Reference>(sAPType, doc, pStream->GetObjNum()); + } + + CPDF_Dictionary* pStreamDict = pStream->GetDict(); + if (!pStreamDict) { + auto pNewDict = pdfium::MakeUnique<CPDF_Dictionary>( + widget_->GetPDFAnnot()->GetDocument()->GetByteStringPool()); + pStreamDict = pNewDict.get(); + pStreamDict->SetNewFor<CPDF_Name>("Type", "XObject"); + pStreamDict->SetNewFor<CPDF_Name>("Subtype", "Form"); + pStreamDict->SetNewFor<CPDF_Number>("FormType", 1); + pStream->InitStream(nullptr, 0, std::move(pNewDict)); + } + pStreamDict->SetMatrixFor("Matrix", widget_->GetMatrix()); + pStreamDict->SetRectFor("BBox", widget_->GetRotatedRect()); + pStream->SetData((uint8_t*)(sContents.c_str()), sContents.GetLength()); +} + +void CPWL_AppStream::Remove(const CFX_ByteString& sAPType) { + dict_->RemoveFor(sAPType); +} + +CFX_ByteString CPWL_AppStream::GetBackgroundAppStream() const { + CFX_Color crBackground = widget_->GetFillPWLColor(); + if (crBackground.nColorType != COLORTYPE_TRANSPARENT) + return CPWL_Utils::GetRectFillAppStream(widget_->GetRotatedRect(), + crBackground); + + return CFX_ByteString(); +} + +CFX_ByteString CPWL_AppStream::GetBorderAppStream() const { + CFX_FloatRect rcWindow = widget_->GetRotatedRect(); + CFX_Color crBorder = widget_->GetBorderPWLColor(); + CFX_Color crBackground = widget_->GetFillPWLColor(); + CFX_Color crLeftTop; + CFX_Color crRightBottom; + + float fBorderWidth = static_cast<float>(widget_->GetBorderWidth()); + CPWL_Dash dsBorder(3, 0, 0); + + BorderStyle nBorderStyle = widget_->GetBorderStyle(); + switch (nBorderStyle) { + case BorderStyle::DASH: + dsBorder = CPWL_Dash(3, 3, 0); + break; + case BorderStyle::BEVELED: + fBorderWidth *= 2; + crLeftTop = CFX_Color(COLORTYPE_GRAY, 1); + crRightBottom = crBackground / 2.0f; + break; + case BorderStyle::INSET: + fBorderWidth *= 2; + crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5); + crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75); + break; + default: + break; + } + + return CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, + crLeftTop, crRightBottom, nBorderStyle, + dsBorder); +} |