You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1989 lines
68 KiB
1989 lines
68 KiB
// Copyright 2017 PDFium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
|
|
|
|
#include "fpdfsdk/cpdfsdk_appstream.h"
|
|
|
|
#include <utility>
|
|
|
|
#include "constants/form_flags.h"
|
|
#include "core/fpdfapi/font/cpdf_font.h"
|
|
#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 "core/fpdfapi/parser/fpdf_parser_decode.h"
|
|
#include "core/fpdfdoc/cba_fontmap.h"
|
|
#include "core/fpdfdoc/cpdf_formcontrol.h"
|
|
#include "core/fpdfdoc/cpdf_icon.h"
|
|
#include "core/fpdfdoc/cpvt_word.h"
|
|
#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
|
|
#include "fpdfsdk/cpdfsdk_interactiveform.h"
|
|
#include "fpdfsdk/cpdfsdk_pageview.h"
|
|
#include "fpdfsdk/cpdfsdk_widget.h"
|
|
#include "fpdfsdk/pwl/cpwl_edit.h"
|
|
#include "fpdfsdk/pwl/cpwl_edit_impl.h"
|
|
#include "fpdfsdk/pwl/cpwl_icon.h"
|
|
#include "fpdfsdk/pwl/cpwl_wnd.h"
|
|
#include "third_party/base/ptr_util.h"
|
|
|
|
namespace {
|
|
|
|
// Checkbox & radiobutton styles.
|
|
enum class CheckStyle { kCheck = 0, kCircle, kCross, kDiamond, kSquare, kStar };
|
|
|
|
// Pushbutton layout styles.
|
|
enum class ButtonStyle {
|
|
kLabel = 0,
|
|
kIcon,
|
|
kIconTopLabelBottom,
|
|
kIconBottomLabelTop,
|
|
kIconLeftLabelRight,
|
|
kIconRightLabelLeft,
|
|
kLabelOverIcon
|
|
};
|
|
|
|
const char kAppendRectOperator[] = "re";
|
|
const char kConcatMatrixOperator[] = "cm";
|
|
const char kCurveToOperator[] = "c";
|
|
const char kEndPathNoFillOrStrokeOperator[] = "n";
|
|
const char kFillOperator[] = "f";
|
|
const char kFillEvenOddOperator[] = "f*";
|
|
const char kInvokeNamedXObjectOperator[] = "Do";
|
|
const char kLineToOperator[] = "l";
|
|
const char kMarkedSequenceBeginOperator[] = "BMC";
|
|
const char kMarkedSequenceEndOperator[] = "EMC";
|
|
const char kMoveTextPositionOperator[] = "Td";
|
|
const char kMoveToOperator[] = "m";
|
|
const char kSetCharacterSpacingOperator[] = "Tc";
|
|
const char kSetCMYKOperator[] = "k";
|
|
const char kSetCMKYStrokedOperator[] = "K";
|
|
const char kSetDashOperator[] = "d";
|
|
const char kSetGrayOperator[] = "g";
|
|
const char kSetGrayStrokedOperator[] = "G";
|
|
const char kSetLineCapStyleOperator[] = "J";
|
|
const char kSetLineJoinStyleOperator[] = "j";
|
|
const char kSetLineWidthOperator[] = "w";
|
|
const char kSetNonZeroWindingClipOperator[] = "W";
|
|
const char kSetRGBOperator[] = "rg";
|
|
const char kSetRGBStrokedOperator[] = "RG";
|
|
const char kSetTextFontAndSizeOperator[] = "Tf";
|
|
const char kShowTextOperator[] = "Tj";
|
|
const char kStateRestoreOperator[] = "Q";
|
|
const char kStateSaveOperator[] = "q";
|
|
const char kStrokeOperator[] = "S";
|
|
const char kTextBeginOperator[] = "BT";
|
|
const char kTextEndOperator[] = "ET";
|
|
|
|
class AutoClosedCommand {
|
|
public:
|
|
AutoClosedCommand(std::ostringstream* stream,
|
|
ByteString open,
|
|
ByteString close)
|
|
: stream_(stream), close_(close) {
|
|
*stream_ << open << "\n";
|
|
}
|
|
|
|
virtual ~AutoClosedCommand() { *stream_ << close_ << "\n"; }
|
|
|
|
private:
|
|
std::ostringstream* stream_;
|
|
ByteString close_;
|
|
};
|
|
|
|
class AutoClosedQCommand final : public AutoClosedCommand {
|
|
public:
|
|
explicit AutoClosedQCommand(std::ostringstream* stream)
|
|
: AutoClosedCommand(stream, kStateSaveOperator, kStateRestoreOperator) {}
|
|
~AutoClosedQCommand() override {}
|
|
};
|
|
|
|
ByteString GetColorAppStream(const CFX_Color& color,
|
|
const bool& bFillOrStroke) {
|
|
std::ostringstream sColorStream;
|
|
|
|
switch (color.nColorType) {
|
|
case CFX_Color::kRGB:
|
|
sColorStream << color.fColor1 << " " << color.fColor2 << " "
|
|
<< color.fColor3 << " "
|
|
<< (bFillOrStroke ? kSetRGBOperator : kSetRGBStrokedOperator)
|
|
<< "\n";
|
|
break;
|
|
case CFX_Color::kGray:
|
|
sColorStream << color.fColor1 << " "
|
|
<< (bFillOrStroke ? kSetGrayOperator
|
|
: kSetGrayStrokedOperator)
|
|
<< "\n";
|
|
break;
|
|
case CFX_Color::kCMYK:
|
|
sColorStream << color.fColor1 << " " << color.fColor2 << " "
|
|
<< color.fColor3 << " " << color.fColor4 << " "
|
|
<< (bFillOrStroke ? kSetCMYKOperator
|
|
: kSetCMKYStrokedOperator)
|
|
<< "\n";
|
|
break;
|
|
}
|
|
|
|
return ByteString(sColorStream);
|
|
}
|
|
|
|
ByteString GetAP_Check(const CFX_FloatRect& crBBox) {
|
|
const float fWidth = crBBox.Width();
|
|
const float fHeight = crBBox.Height();
|
|
|
|
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 << " " << kMoveToOperator << "\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 << " " << kCurveToOperator << "\n";
|
|
}
|
|
|
|
return ByteString(csAP);
|
|
}
|
|
|
|
ByteString GetAP_Circle(const CFX_FloatRect& crBBox) {
|
|
std::ostringstream csAP;
|
|
|
|
float fWidth = crBBox.Width();
|
|
float fHeight = crBBox.Height();
|
|
|
|
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 << " " << kMoveToOperator << "\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
|
|
<< " " << kCurveToOperator << "\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 << " "
|
|
<< kCurveToOperator << "\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
|
|
<< " " << kCurveToOperator << "\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 << " "
|
|
<< kCurveToOperator << "\n";
|
|
|
|
return ByteString(csAP);
|
|
}
|
|
|
|
ByteString GetAP_Cross(const CFX_FloatRect& crBBox) {
|
|
std::ostringstream csAP;
|
|
|
|
csAP << crBBox.left << " " << crBBox.top << " " << kMoveToOperator << "\n";
|
|
csAP << crBBox.right << " " << crBBox.bottom << " " << kLineToOperator
|
|
<< "\n";
|
|
csAP << crBBox.left << " " << crBBox.bottom << " " << kMoveToOperator << "\n";
|
|
csAP << crBBox.right << " " << crBBox.top << " " << kLineToOperator << "\n";
|
|
|
|
return ByteString(csAP);
|
|
}
|
|
|
|
ByteString GetAP_Diamond(const CFX_FloatRect& crBBox) {
|
|
std::ostringstream csAP;
|
|
|
|
float fWidth = crBBox.Width();
|
|
float fHeight = crBBox.Height();
|
|
|
|
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 << " " << kMoveToOperator << "\n";
|
|
csAP << pt2.x << " " << pt2.y << " " << kLineToOperator << "\n";
|
|
csAP << pt3.x << " " << pt3.y << " " << kLineToOperator << "\n";
|
|
csAP << pt4.x << " " << pt4.y << " " << kLineToOperator << "\n";
|
|
csAP << pt1.x << " " << pt1.y << " " << kLineToOperator << "\n";
|
|
|
|
return ByteString(csAP);
|
|
}
|
|
|
|
ByteString GetAP_Square(const CFX_FloatRect& crBBox) {
|
|
std::ostringstream csAP;
|
|
|
|
csAP << crBBox.left << " " << crBBox.top << " " << kMoveToOperator << "\n";
|
|
csAP << crBBox.right << " " << crBBox.top << " " << kLineToOperator << "\n";
|
|
csAP << crBBox.right << " " << crBBox.bottom << " " << kLineToOperator
|
|
<< "\n";
|
|
csAP << crBBox.left << " " << crBBox.bottom << " " << kLineToOperator << "\n";
|
|
csAP << crBBox.left << " " << crBBox.top << " " << kLineToOperator << "\n";
|
|
|
|
return ByteString(csAP);
|
|
}
|
|
|
|
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] << " " << kMoveToOperator << "\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] << " " << kLineToOperator << "\n";
|
|
}
|
|
|
|
return ByteString(csAP);
|
|
}
|
|
|
|
ByteString GetAP_HalfCircle(const CFX_FloatRect& crBBox, float fRotate) {
|
|
std::ostringstream csAP;
|
|
|
|
float fWidth = crBBox.Width();
|
|
float fHeight = crBBox.Height();
|
|
|
|
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 << " " << kConcatMatrixOperator << "\n";
|
|
|
|
csAP << pt1.x << " " << pt1.y << " " << kMoveToOperator << "\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
|
|
<< " " << kCurveToOperator << "\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 << " "
|
|
<< kCurveToOperator << "\n";
|
|
|
|
return ByteString(csAP);
|
|
}
|
|
|
|
ByteString GetAppStream_Check(const CFX_FloatRect& rcBBox,
|
|
const CFX_Color& crText) {
|
|
std::ostringstream sAP;
|
|
{
|
|
AutoClosedQCommand q(&sAP);
|
|
sAP << GetColorAppStream(crText, true) << GetAP_Check(rcBBox)
|
|
<< kFillOperator << "\n";
|
|
}
|
|
return ByteString(sAP);
|
|
}
|
|
|
|
ByteString GetAppStream_Circle(const CFX_FloatRect& rcBBox,
|
|
const CFX_Color& crText) {
|
|
std::ostringstream sAP;
|
|
{
|
|
AutoClosedQCommand q(&sAP);
|
|
sAP << GetColorAppStream(crText, true) << GetAP_Circle(rcBBox)
|
|
<< kFillOperator << "\n";
|
|
}
|
|
return ByteString(sAP);
|
|
}
|
|
|
|
ByteString GetAppStream_Cross(const CFX_FloatRect& rcBBox,
|
|
const CFX_Color& crText) {
|
|
std::ostringstream sAP;
|
|
{
|
|
AutoClosedQCommand q(&sAP);
|
|
sAP << GetColorAppStream(crText, false) << GetAP_Cross(rcBBox)
|
|
<< kStrokeOperator << "\n";
|
|
}
|
|
return ByteString(sAP);
|
|
}
|
|
|
|
ByteString GetAppStream_Diamond(const CFX_FloatRect& rcBBox,
|
|
const CFX_Color& crText) {
|
|
std::ostringstream sAP;
|
|
{
|
|
AutoClosedQCommand q(&sAP);
|
|
sAP << "1 " << kSetLineWidthOperator << "\n"
|
|
<< GetColorAppStream(crText, true) << GetAP_Diamond(rcBBox)
|
|
<< kFillOperator << "\n";
|
|
}
|
|
return ByteString(sAP);
|
|
}
|
|
|
|
ByteString GetAppStream_Square(const CFX_FloatRect& rcBBox,
|
|
const CFX_Color& crText) {
|
|
std::ostringstream sAP;
|
|
{
|
|
AutoClosedQCommand q(&sAP);
|
|
sAP << GetColorAppStream(crText, true) << GetAP_Square(rcBBox)
|
|
<< kFillOperator << "\n";
|
|
}
|
|
return ByteString(sAP);
|
|
}
|
|
|
|
ByteString GetAppStream_Star(const CFX_FloatRect& rcBBox,
|
|
const CFX_Color& crText) {
|
|
std::ostringstream sAP;
|
|
{
|
|
AutoClosedQCommand q(&sAP);
|
|
sAP << GetColorAppStream(crText, true) << GetAP_Star(rcBBox)
|
|
<< kFillOperator << "\n";
|
|
}
|
|
return ByteString(sAP);
|
|
}
|
|
|
|
ByteString GetCircleFillAppStream(const CFX_FloatRect& rect,
|
|
const CFX_Color& color) {
|
|
std::ostringstream sAppStream;
|
|
ByteString sColor = GetColorAppStream(color, true);
|
|
if (sColor.GetLength() > 0) {
|
|
AutoClosedQCommand q(&sAppStream);
|
|
sAppStream << sColor << GetAP_Circle(rect) << kFillOperator << "\n";
|
|
}
|
|
return ByteString(sAppStream);
|
|
}
|
|
|
|
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;
|
|
ByteString sColor;
|
|
|
|
if (fWidth > 0.0f) {
|
|
AutoClosedQCommand q(&sAppStream);
|
|
|
|
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 = GetColorAppStream(color, false);
|
|
if (sColor.GetLength() > 0) {
|
|
AutoClosedQCommand q2(&sAppStream);
|
|
sAppStream << fWidth << " " << kSetLineWidthOperator << "\n"
|
|
<< sColor << GetAP_Circle(rect_by_2) << " "
|
|
<< kStrokeOperator << "\n";
|
|
}
|
|
} break;
|
|
case BorderStyle::DASH: {
|
|
sColor = GetColorAppStream(color, false);
|
|
if (sColor.GetLength() > 0) {
|
|
AutoClosedQCommand q2(&sAppStream);
|
|
sAppStream << fWidth << " " << kSetLineWidthOperator << "\n"
|
|
<< "[" << dash.nDash << " " << dash.nGap << "] "
|
|
<< dash.nPhase << " " << kSetDashOperator << "\n"
|
|
<< sColor << GetAP_Circle(rect_by_2) << " "
|
|
<< kStrokeOperator << "\n";
|
|
}
|
|
} break;
|
|
case BorderStyle::BEVELED: {
|
|
sColor = GetColorAppStream(color, false);
|
|
if (sColor.GetLength() > 0) {
|
|
AutoClosedQCommand q2(&sAppStream);
|
|
sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
|
|
<< sColor << GetAP_Circle(rect) << " " << kStrokeOperator
|
|
<< "\n";
|
|
}
|
|
|
|
sColor = GetColorAppStream(crLeftTop, false);
|
|
if (sColor.GetLength() > 0) {
|
|
AutoClosedQCommand q2(&sAppStream);
|
|
sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
|
|
<< sColor << GetAP_HalfCircle(rect_by_75, FX_PI / 4.0f)
|
|
<< " " << kStrokeOperator << "\n";
|
|
}
|
|
|
|
sColor = GetColorAppStream(crRightBottom, false);
|
|
if (sColor.GetLength() > 0) {
|
|
AutoClosedQCommand q2(&sAppStream);
|
|
sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
|
|
<< sColor << GetAP_HalfCircle(rect_by_75, FX_PI * 5 / 4.0f)
|
|
<< " " << kStrokeOperator << "\n";
|
|
}
|
|
} break;
|
|
case BorderStyle::INSET: {
|
|
sColor = GetColorAppStream(color, false);
|
|
if (sColor.GetLength() > 0) {
|
|
AutoClosedQCommand q2(&sAppStream);
|
|
sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
|
|
<< sColor << GetAP_Circle(rect) << " " << kStrokeOperator
|
|
<< "\n";
|
|
}
|
|
|
|
sColor = GetColorAppStream(crLeftTop, false);
|
|
if (sColor.GetLength() > 0) {
|
|
AutoClosedQCommand q2(&sAppStream);
|
|
sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
|
|
<< sColor << GetAP_HalfCircle(rect_by_75, FX_PI / 4.0f)
|
|
<< " " << kStrokeOperator << "\n";
|
|
}
|
|
|
|
sColor = GetColorAppStream(crRightBottom, false);
|
|
if (sColor.GetLength() > 0) {
|
|
AutoClosedQCommand q2(&sAppStream);
|
|
sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
|
|
<< sColor << GetAP_HalfCircle(rect_by_75, FX_PI * 5 / 4.0f)
|
|
<< " " << kStrokeOperator << "\n";
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
return ByteString(sAppStream);
|
|
}
|
|
|
|
ByteString GetCheckBoxAppStream(const CFX_FloatRect& rcBBox,
|
|
CheckStyle nStyle,
|
|
const CFX_Color& crText) {
|
|
CFX_FloatRect rcCenter = rcBBox.GetCenterSquare();
|
|
switch (nStyle) {
|
|
default:
|
|
case CheckStyle::kCheck:
|
|
return GetAppStream_Check(rcCenter, crText);
|
|
case CheckStyle::kCircle:
|
|
rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
|
|
return GetAppStream_Circle(rcCenter, crText);
|
|
case CheckStyle::kCross:
|
|
return GetAppStream_Cross(rcCenter, crText);
|
|
case CheckStyle::kDiamond:
|
|
rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
|
|
return GetAppStream_Diamond(rcCenter, crText);
|
|
case CheckStyle::kSquare:
|
|
rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
|
|
return GetAppStream_Square(rcCenter, crText);
|
|
case CheckStyle::kStar:
|
|
rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
|
|
return GetAppStream_Star(rcCenter, crText);
|
|
}
|
|
}
|
|
|
|
ByteString GetRadioButtonAppStream(const CFX_FloatRect& rcBBox,
|
|
CheckStyle nStyle,
|
|
const CFX_Color& crText) {
|
|
CFX_FloatRect rcCenter = rcBBox.GetCenterSquare();
|
|
switch (nStyle) {
|
|
default:
|
|
case CheckStyle::kCheck:
|
|
return GetAppStream_Check(rcCenter, crText);
|
|
case CheckStyle::kCircle:
|
|
rcCenter.ScaleFromCenterPoint(1.0f / 2.0f);
|
|
return GetAppStream_Circle(rcCenter, crText);
|
|
case CheckStyle::kCross:
|
|
return GetAppStream_Cross(rcCenter, crText);
|
|
case CheckStyle::kDiamond:
|
|
rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
|
|
return GetAppStream_Diamond(rcCenter, crText);
|
|
case CheckStyle::kSquare:
|
|
rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
|
|
return GetAppStream_Square(rcCenter, crText);
|
|
case CheckStyle::kStar:
|
|
rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
|
|
return GetAppStream_Star(rcCenter, crText);
|
|
}
|
|
}
|
|
|
|
ByteString GetFontSetString(IPVT_FontMap* pFontMap,
|
|
int32_t nFontIndex,
|
|
float fFontSize) {
|
|
if (!pFontMap)
|
|
return ByteString();
|
|
|
|
ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);
|
|
if (sFontAlias.GetLength() <= 0 || fFontSize <= 0)
|
|
return ByteString();
|
|
|
|
std::ostringstream sRet;
|
|
sRet << "/" << sFontAlias << " " << fFontSize << " "
|
|
<< kSetTextFontAndSizeOperator << "\n";
|
|
return ByteString(sRet);
|
|
}
|
|
|
|
ByteString GetWordRenderString(const ByteString& strWords) {
|
|
if (strWords.GetLength() > 0) {
|
|
return PDF_EncodeString(strWords, false) + " " + kShowTextOperator + "\n";
|
|
}
|
|
return ByteString();
|
|
}
|
|
|
|
ByteString GetEditAppStream(CPWL_EditImpl* pEdit,
|
|
const CFX_PointF& ptOffset,
|
|
bool bContinuous,
|
|
uint16_t SubWord) {
|
|
CPWL_EditImpl_Iterator* pIterator = pEdit->GetIterator();
|
|
pIterator->SetAt(0);
|
|
|
|
std::ostringstream sEditStream;
|
|
std::ostringstream sWords;
|
|
int32_t nCurFontIndex = -1;
|
|
CFX_PointF ptOld;
|
|
CFX_PointF ptNew;
|
|
CPVT_WordPlace oldplace;
|
|
|
|
while (pIterator->NextWord()) {
|
|
CPVT_WordPlace place = pIterator->GetAt();
|
|
if (bContinuous) {
|
|
if (place.LineCmp(oldplace) != 0) {
|
|
if (sWords.tellp() > 0) {
|
|
sEditStream << GetWordRenderString(ByteString(sWords));
|
|
sWords.str("");
|
|
}
|
|
|
|
CPVT_Word word;
|
|
if (pIterator->GetWord(word)) {
|
|
ptNew = CFX_PointF(word.ptWord.x + ptOffset.x,
|
|
word.ptWord.y + ptOffset.y);
|
|
} else {
|
|
CPVT_Line line;
|
|
pIterator->GetLine(line);
|
|
ptNew = CFX_PointF(line.ptLine.x + ptOffset.x,
|
|
line.ptLine.y + ptOffset.y);
|
|
}
|
|
|
|
if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
|
|
sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " "
|
|
<< kMoveTextPositionOperator << "\n";
|
|
|
|
ptOld = ptNew;
|
|
}
|
|
}
|
|
|
|
CPVT_Word word;
|
|
if (pIterator->GetWord(word)) {
|
|
if (word.nFontIndex != nCurFontIndex) {
|
|
if (sWords.tellp() > 0) {
|
|
sEditStream << GetWordRenderString(ByteString(sWords));
|
|
sWords.str("");
|
|
}
|
|
sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
|
|
word.fFontSize);
|
|
nCurFontIndex = word.nFontIndex;
|
|
}
|
|
|
|
sWords << pEdit->GetPDFWordString(nCurFontIndex, word.Word, SubWord);
|
|
}
|
|
|
|
oldplace = place;
|
|
} else {
|
|
CPVT_Word word;
|
|
if (pIterator->GetWord(word)) {
|
|
ptNew =
|
|
CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);
|
|
|
|
if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
|
|
sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " "
|
|
<< kMoveTextPositionOperator << "\n";
|
|
ptOld = ptNew;
|
|
}
|
|
|
|
if (word.nFontIndex != nCurFontIndex) {
|
|
sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
|
|
word.fFontSize);
|
|
nCurFontIndex = word.nFontIndex;
|
|
}
|
|
|
|
sEditStream << GetWordRenderString(
|
|
pEdit->GetPDFWordString(nCurFontIndex, word.Word, SubWord));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sWords.tellp() > 0) {
|
|
sEditStream << GetWordRenderString(ByteString(sWords));
|
|
sWords.str("");
|
|
}
|
|
|
|
std::ostringstream sAppStream;
|
|
if (sEditStream.tellp() > 0) {
|
|
float fCharSpace = pEdit->GetCharSpace();
|
|
if (!IsFloatZero(fCharSpace))
|
|
sAppStream << fCharSpace << " " << kSetCharacterSpacingOperator << "\n";
|
|
|
|
sAppStream << sEditStream.str();
|
|
}
|
|
|
|
return ByteString(sAppStream);
|
|
}
|
|
|
|
ByteString GenerateIconAppStream(CPDF_IconFit& fit,
|
|
CPDF_Stream* pIconStream,
|
|
const CFX_FloatRect& rcIcon) {
|
|
if (rcIcon.IsEmpty() || !pIconStream)
|
|
return ByteString();
|
|
|
|
CPWL_Wnd::CreateParams cp;
|
|
cp.dwFlags = PWS_VISIBLE;
|
|
|
|
CPWL_Icon icon(cp, pdfium::MakeUnique<CPDF_Icon>(pIconStream), &fit);
|
|
icon.Realize();
|
|
if (!icon.Move(rcIcon, false, false))
|
|
return ByteString();
|
|
|
|
ByteString sAlias = icon.GetImageAlias();
|
|
if (sAlias.GetLength() <= 0)
|
|
return ByteString();
|
|
|
|
CFX_FloatRect rcPlate = icon.GetClientRect();
|
|
CFX_Matrix mt = icon.GetImageMatrix().GetInverse();
|
|
|
|
float fHScale;
|
|
float fVScale;
|
|
std::tie(fHScale, fVScale) = icon.GetScale();
|
|
|
|
float fx;
|
|
float fy;
|
|
std::tie(fx, fy) = icon.GetImageOffset();
|
|
|
|
std::ostringstream str;
|
|
{
|
|
AutoClosedQCommand q(&str);
|
|
str << rcPlate.left << " " << rcPlate.bottom << " "
|
|
<< rcPlate.right - rcPlate.left << " " << rcPlate.top - rcPlate.bottom
|
|
<< " " << kAppendRectOperator << " " << kSetNonZeroWindingClipOperator
|
|
<< " " << kEndPathNoFillOrStrokeOperator << "\n";
|
|
|
|
str << fHScale << " 0 0 " << fVScale << " " << rcPlate.left + fx << " "
|
|
<< rcPlate.bottom + fy << " " << kConcatMatrixOperator << "\n";
|
|
str << mt.a << " " << mt.b << " " << mt.c << " " << mt.d << " " << mt.e
|
|
<< " " << mt.f << " " << kConcatMatrixOperator << "\n";
|
|
|
|
str << "0 " << kSetGrayOperator << " 0 " << kSetGrayStrokedOperator << " 1 "
|
|
<< kSetLineWidthOperator << " /" << sAlias << " "
|
|
<< kInvokeNamedXObjectOperator << "\n";
|
|
}
|
|
icon.Destroy();
|
|
|
|
return ByteString(str);
|
|
}
|
|
|
|
ByteString GetPushButtonAppStream(const CFX_FloatRect& rcBBox,
|
|
IPVT_FontMap* pFontMap,
|
|
CPDF_Stream* pIconStream,
|
|
CPDF_IconFit& IconFit,
|
|
const WideString& sLabel,
|
|
const CFX_Color& crText,
|
|
float fFontSize,
|
|
ButtonStyle nLayOut) {
|
|
const float fAutoFontScale = 1.0f / 3.0f;
|
|
|
|
auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
|
|
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();
|
|
CFX_FloatRect rcLabel;
|
|
CFX_FloatRect rcIcon;
|
|
float fWidth = 0.0f;
|
|
float fHeight = 0.0f;
|
|
|
|
switch (nLayOut) {
|
|
case ButtonStyle::kLabel:
|
|
rcLabel = rcBBox;
|
|
break;
|
|
case ButtonStyle::kIcon:
|
|
rcIcon = rcBBox;
|
|
break;
|
|
case ButtonStyle::kIconTopLabelBottom:
|
|
if (pIconStream) {
|
|
if (IsFloatZero(fFontSize)) {
|
|
fHeight = rcBBox.Height();
|
|
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 ButtonStyle::kIconBottomLabelTop:
|
|
if (pIconStream) {
|
|
if (IsFloatZero(fFontSize)) {
|
|
fHeight = rcBBox.Height();
|
|
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 ButtonStyle::kIconLeftLabelRight:
|
|
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 ButtonStyle::kIconRightLabelLeft:
|
|
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 ButtonStyle::kLabelOverIcon:
|
|
rcLabel = rcBBox;
|
|
rcIcon = rcBBox;
|
|
break;
|
|
}
|
|
|
|
std::ostringstream sTemp;
|
|
sTemp << GenerateIconAppStream(IconFit, pIconStream, rcIcon);
|
|
|
|
if (!rcLabel.IsEmpty()) {
|
|
pEdit->SetPlateRect(rcLabel);
|
|
ByteString sEdit =
|
|
GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, 0.0f), true, 0);
|
|
if (sEdit.GetLength() > 0) {
|
|
AutoClosedCommand bt(&sTemp, kTextBeginOperator, kTextEndOperator);
|
|
sTemp << GetColorAppStream(crText, true) << sEdit;
|
|
}
|
|
}
|
|
|
|
if (sTemp.tellp() <= 0)
|
|
return ByteString();
|
|
|
|
std::ostringstream sAppStream;
|
|
{
|
|
AutoClosedQCommand q(&sAppStream);
|
|
sAppStream << rcBBox.left << " " << rcBBox.bottom << " "
|
|
<< rcBBox.right - rcBBox.left << " "
|
|
<< rcBBox.top - rcBBox.bottom << " " << kAppendRectOperator
|
|
<< " " << kSetNonZeroWindingClipOperator << " "
|
|
<< kEndPathNoFillOrStrokeOperator << "\n";
|
|
sAppStream << sTemp.str().c_str();
|
|
}
|
|
return ByteString(sAppStream);
|
|
}
|
|
|
|
ByteString GetBorderAppStreamInternal(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;
|
|
ByteString sColor;
|
|
|
|
float fLeft = rect.left;
|
|
float fRight = rect.right;
|
|
float fTop = rect.top;
|
|
float fBottom = rect.bottom;
|
|
|
|
if (fWidth > 0.0f) {
|
|
float fHalfWidth = fWidth / 2.0f;
|
|
AutoClosedQCommand q(&sAppStream);
|
|
|
|
switch (nStyle) {
|
|
default:
|
|
case BorderStyle::SOLID:
|
|
sColor = GetColorAppStream(color, true);
|
|
if (sColor.GetLength() > 0) {
|
|
sAppStream << sColor;
|
|
sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
|
|
<< fTop - fBottom << " " << kAppendRectOperator << "\n";
|
|
sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
|
|
<< fRight - fLeft - fWidth * 2 << " "
|
|
<< fTop - fBottom - fWidth * 2 << " "
|
|
<< kAppendRectOperator << "\n";
|
|
sAppStream << kFillEvenOddOperator << "\n";
|
|
}
|
|
break;
|
|
case BorderStyle::DASH:
|
|
sColor = GetColorAppStream(color, false);
|
|
if (sColor.GetLength() > 0) {
|
|
sAppStream << sColor;
|
|
sAppStream << fWidth << " " << kSetLineWidthOperator << " ["
|
|
<< dash.nDash << " " << dash.nGap << "] " << dash.nPhase
|
|
<< " " << kSetDashOperator << "\n";
|
|
sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 << " "
|
|
<< kMoveToOperator << "\n";
|
|
sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2 << " "
|
|
<< kLineToOperator << "\n";
|
|
sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2 << " "
|
|
<< kLineToOperator << "\n";
|
|
sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2
|
|
<< " " << kLineToOperator << "\n";
|
|
sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 << " "
|
|
<< kLineToOperator << " " << kStrokeOperator << "\n";
|
|
}
|
|
break;
|
|
case BorderStyle::BEVELED:
|
|
case BorderStyle::INSET:
|
|
sColor = GetColorAppStream(crLeftTop, true);
|
|
if (sColor.GetLength() > 0) {
|
|
sAppStream << sColor;
|
|
sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
|
|
<< kMoveToOperator << "\n";
|
|
sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth << " "
|
|
<< kLineToOperator << "\n";
|
|
sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth << " "
|
|
<< kLineToOperator << "\n";
|
|
sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
|
|
<< " " << kLineToOperator << "\n";
|
|
sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
|
|
<< " " << kLineToOperator << "\n";
|
|
sAppStream << fLeft + fHalfWidth * 2 << " "
|
|
<< fBottom + fHalfWidth * 2 << " " << kLineToOperator
|
|
<< " " << kFillOperator << "\n";
|
|
}
|
|
|
|
sColor = GetColorAppStream(crRightBottom, true);
|
|
if (sColor.GetLength() > 0) {
|
|
sAppStream << sColor;
|
|
sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth << " "
|
|
<< kMoveToOperator << "\n";
|
|
sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth
|
|
<< " " << kLineToOperator << "\n";
|
|
sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
|
|
<< kLineToOperator << "\n";
|
|
sAppStream << fLeft + fHalfWidth * 2 << " "
|
|
<< fBottom + fHalfWidth * 2 << " " << kLineToOperator
|
|
<< "\n";
|
|
sAppStream << fRight - fHalfWidth * 2 << " "
|
|
<< fBottom + fHalfWidth * 2 << " " << kLineToOperator
|
|
<< "\n";
|
|
sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
|
|
<< " " << kLineToOperator << " " << kFillOperator << "\n";
|
|
}
|
|
|
|
sColor = GetColorAppStream(color, true);
|
|
if (sColor.GetLength() > 0) {
|
|
sAppStream << sColor;
|
|
sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
|
|
<< fTop - fBottom << " " << kAppendRectOperator << "\n";
|
|
sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
|
|
<< fRight - fLeft - fHalfWidth * 2 << " "
|
|
<< fTop - fBottom - fHalfWidth * 2 << " "
|
|
<< kAppendRectOperator << " " << kFillEvenOddOperator
|
|
<< "\n";
|
|
}
|
|
break;
|
|
case BorderStyle::UNDERLINE:
|
|
sColor = GetColorAppStream(color, false);
|
|
if (sColor.GetLength() > 0) {
|
|
sAppStream << sColor;
|
|
sAppStream << fWidth << " " << kSetLineWidthOperator << "\n";
|
|
sAppStream << fLeft << " " << fBottom + fWidth / 2 << " "
|
|
<< kMoveToOperator << "\n";
|
|
sAppStream << fRight << " " << fBottom + fWidth / 2 << " "
|
|
<< kLineToOperator << " " << kStrokeOperator << "\n";
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ByteString(sAppStream);
|
|
}
|
|
|
|
ByteString GetDropButtonAppStream(const CFX_FloatRect& rcBBox) {
|
|
if (rcBBox.IsEmpty())
|
|
return ByteString();
|
|
|
|
std::ostringstream sAppStream;
|
|
{
|
|
AutoClosedQCommand q(&sAppStream);
|
|
sAppStream << GetColorAppStream(CFX_Color(CFX_Color::kRGB, 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 << " " << kAppendRectOperator
|
|
<< " " << kFillOperator << "\n";
|
|
}
|
|
|
|
{
|
|
AutoClosedQCommand q(&sAppStream);
|
|
sAppStream << GetBorderAppStreamInternal(
|
|
rcBBox, 2, CFX_Color(CFX_Color::kGray, 0),
|
|
CFX_Color(CFX_Color::kGray, 1), CFX_Color(CFX_Color::kGray, 0.5),
|
|
BorderStyle::BEVELED, CPWL_Dash(3, 0, 0));
|
|
}
|
|
|
|
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)) {
|
|
AutoClosedQCommand q(&sAppStream);
|
|
sAppStream << " 0 " << kSetGrayOperator << "\n"
|
|
<< ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " "
|
|
<< kMoveToOperator << "\n"
|
|
<< ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " "
|
|
<< kLineToOperator << "\n"
|
|
<< ptCenter.x << " " << ptCenter.y - 1.5f << " "
|
|
<< kLineToOperator << "\n"
|
|
<< ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " "
|
|
<< kLineToOperator << " " << kFillOperator << "\n";
|
|
}
|
|
|
|
return ByteString(sAppStream);
|
|
}
|
|
|
|
ByteString GetRectFillAppStream(const CFX_FloatRect& rect,
|
|
const CFX_Color& color) {
|
|
std::ostringstream sAppStream;
|
|
ByteString sColor = GetColorAppStream(color, true);
|
|
if (sColor.GetLength() > 0) {
|
|
AutoClosedQCommand q(&sAppStream);
|
|
sAppStream << sColor << rect.left << " " << rect.bottom << " "
|
|
<< rect.right - rect.left << " " << rect.top - rect.bottom << " "
|
|
<< kAppendRectOperator << " " << kFillOperator << "\n";
|
|
}
|
|
|
|
return ByteString(sAppStream);
|
|
}
|
|
|
|
void SetDefaultIconName(CPDF_Stream* pIcon, const char* name) {
|
|
if (!pIcon)
|
|
return;
|
|
|
|
CPDF_Dictionary* pImageDict = pIcon->GetDict();
|
|
if (!pImageDict)
|
|
return;
|
|
|
|
if (pImageDict->KeyExist("Name"))
|
|
return;
|
|
|
|
pImageDict->SetNewFor<CPDF_String>("Name", name, false);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
CPDFSDK_AppStream::CPDFSDK_AppStream(CPDFSDK_Widget* widget,
|
|
CPDF_Dictionary* dict)
|
|
: widget_(widget), dict_(dict) {}
|
|
|
|
CPDFSDK_AppStream::~CPDFSDK_AppStream() {}
|
|
|
|
void CPDFSDK_AppStream::SetAsPushButton() {
|
|
CPDF_FormControl* pControl = widget_->GetFormControl();
|
|
CFX_FloatRect rcWindow = widget_->GetRotatedRect();
|
|
ButtonStyle nLayout = ButtonStyle::kLabel;
|
|
switch (pControl->GetTextPosition()) {
|
|
case TEXTPOS_ICON:
|
|
nLayout = ButtonStyle::kIcon;
|
|
break;
|
|
case TEXTPOS_BELOW:
|
|
nLayout = ButtonStyle::kIconTopLabelBottom;
|
|
break;
|
|
case TEXTPOS_ABOVE:
|
|
nLayout = ButtonStyle::kIconBottomLabelTop;
|
|
break;
|
|
case TEXTPOS_RIGHT:
|
|
nLayout = ButtonStyle::kIconLeftLabelRight;
|
|
break;
|
|
case TEXTPOS_LEFT:
|
|
nLayout = ButtonStyle::kIconRightLabelLeft;
|
|
break;
|
|
case TEXTPOS_OVERLAID:
|
|
nLayout = ButtonStyle::kLabelOverIcon;
|
|
break;
|
|
default:
|
|
nLayout = ButtonStyle::kLabel;
|
|
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(CFX_Color::kGray, 1);
|
|
crRightBottom = crBackground / 2.0f;
|
|
break;
|
|
case BorderStyle::INSET:
|
|
fBorderWidth *= 2;
|
|
crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
|
|
crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
|
|
CFX_Color crText(CFX_Color::kGray, 0);
|
|
ByteString csNameTag;
|
|
CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
|
|
Optional<CFX_Color::Type> color = da.GetColor(fc);
|
|
if (color) {
|
|
iColorType = *color;
|
|
crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
|
|
}
|
|
|
|
float fFontSize;
|
|
Optional<ByteString> font = da.GetFont(&fFontSize);
|
|
if (font)
|
|
csNameTag = *font;
|
|
else
|
|
fFontSize = 12.0f;
|
|
|
|
WideString csWCaption;
|
|
WideString csNormalCaption;
|
|
WideString csRolloverCaption;
|
|
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();
|
|
|
|
SetDefaultIconName(pNormalIcon, "ImgA");
|
|
SetDefaultIconName(pRolloverIcon, "ImgB");
|
|
SetDefaultIconName(pDownIcon, "ImgC");
|
|
|
|
CBA_FontMap font_map(widget_->GetPDFPage()->GetDocument(),
|
|
widget_->GetPDFAnnot()->GetAnnotDict());
|
|
font_map.SetAPType("N");
|
|
|
|
CPDF_IconFit iconFit = pControl->GetIconFit();
|
|
ByteString csAP =
|
|
GetRectFillAppStream(rcWindow, crBackground) +
|
|
GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
|
|
crRightBottom, nBorderStyle, dsBorder) +
|
|
GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
|
|
&font_map, pNormalIcon, iconFit, csNormalCaption,
|
|
crText, fFontSize, nLayout);
|
|
|
|
Write("N", csAP, ByteString());
|
|
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 =
|
|
GetRectFillAppStream(rcWindow, crBackground) +
|
|
GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
|
|
crRightBottom, nBorderStyle, dsBorder) +
|
|
GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
|
|
&font_map, pRolloverIcon, iconFit,
|
|
csRolloverCaption, crText, fFontSize, nLayout);
|
|
|
|
Write("R", csAP, ByteString());
|
|
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(CFX_Color::kGray, 0);
|
|
crRightBottom = CFX_Color(CFX_Color::kGray, 1);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
font_map.SetAPType("D");
|
|
|
|
csAP =
|
|
GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
|
|
GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
|
|
crRightBottom, nBorderStyle, dsBorder) +
|
|
GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
|
|
&font_map, pDownIcon, iconFit, csDownCaption,
|
|
crText, fFontSize, nLayout);
|
|
|
|
Write("D", csAP, ByteString());
|
|
if (pDownIcon)
|
|
AddImage("D", pDownIcon);
|
|
} else {
|
|
Remove("D");
|
|
Remove("R");
|
|
}
|
|
}
|
|
|
|
void CPDFSDK_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(CFX_Color::kGray, 1);
|
|
crRightBottom = crBackground / 2.0f;
|
|
break;
|
|
case BorderStyle::INSET:
|
|
fBorderWidth *= 2;
|
|
crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
|
|
crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
CFX_FloatRect rcWindow = widget_->GetRotatedRect();
|
|
CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
|
|
CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
|
|
Optional<CFX_Color::Type> color = da.GetColor(fc);
|
|
if (color) {
|
|
iColorType = *color;
|
|
crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
|
|
}
|
|
|
|
CheckStyle nStyle = CheckStyle::kCheck;
|
|
WideString csWCaption = pControl->GetNormalCaption();
|
|
if (csWCaption.GetLength() > 0) {
|
|
switch (csWCaption[0]) {
|
|
case L'l':
|
|
nStyle = CheckStyle::kCircle;
|
|
break;
|
|
case L'8':
|
|
nStyle = CheckStyle::kCross;
|
|
break;
|
|
case L'u':
|
|
nStyle = CheckStyle::kDiamond;
|
|
break;
|
|
case L'n':
|
|
nStyle = CheckStyle::kSquare;
|
|
break;
|
|
case L'H':
|
|
nStyle = CheckStyle::kStar;
|
|
break;
|
|
case L'4':
|
|
default:
|
|
nStyle = CheckStyle::kCheck;
|
|
}
|
|
}
|
|
|
|
ByteString csAP_N_ON =
|
|
GetRectFillAppStream(rcWindow, crBackground) +
|
|
GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
|
|
crRightBottom, nBorderStyle, dsBorder);
|
|
|
|
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(CFX_Color::kGray, 0);
|
|
crRightBottom = CFX_Color(CFX_Color::kGray, 1);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ByteString csAP_D_ON =
|
|
GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
|
|
GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
|
|
crRightBottom, nBorderStyle, dsBorder);
|
|
|
|
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");
|
|
|
|
ByteString csAS = widget_->GetAppState();
|
|
if (csAS.IsEmpty())
|
|
widget_->SetAppState("Off");
|
|
}
|
|
|
|
void CPDFSDK_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(CFX_Color::kGray, 1);
|
|
crRightBottom = crBackground / 2.0f;
|
|
break;
|
|
case BorderStyle::INSET:
|
|
fBorderWidth *= 2;
|
|
crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
|
|
crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
CFX_FloatRect rcWindow = widget_->GetRotatedRect();
|
|
CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
|
|
CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
|
|
Optional<CFX_Color::Type> color = da.GetColor(fc);
|
|
if (color) {
|
|
iColorType = *color;
|
|
crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
|
|
}
|
|
|
|
CheckStyle nStyle = CheckStyle::kCircle;
|
|
WideString csWCaption = pControl->GetNormalCaption();
|
|
if (csWCaption.GetLength() > 0) {
|
|
switch (csWCaption[0]) {
|
|
case L'8':
|
|
nStyle = CheckStyle::kCross;
|
|
break;
|
|
case L'u':
|
|
nStyle = CheckStyle::kDiamond;
|
|
break;
|
|
case L'n':
|
|
nStyle = CheckStyle::kSquare;
|
|
break;
|
|
case L'H':
|
|
nStyle = CheckStyle::kStar;
|
|
break;
|
|
case L'4':
|
|
nStyle = CheckStyle::kCheck;
|
|
break;
|
|
case L'l':
|
|
default:
|
|
nStyle = CheckStyle::kCircle;
|
|
}
|
|
}
|
|
|
|
ByteString csAP_N_ON;
|
|
CFX_FloatRect rcCenter = rcWindow.GetCenterSquare().GetDeflated(1.0f, 1.0f);
|
|
if (nStyle == CheckStyle::kCircle) {
|
|
if (nBorderStyle == BorderStyle::BEVELED) {
|
|
crLeftTop = CFX_Color(CFX_Color::kGray, 1);
|
|
crRightBottom = crBackground - 0.25f;
|
|
} else if (nBorderStyle == BorderStyle::INSET) {
|
|
crLeftTop = CFX_Color(CFX_Color::kGray, 0.5f);
|
|
crRightBottom = CFX_Color(CFX_Color::kGray, 0.75f);
|
|
}
|
|
|
|
csAP_N_ON =
|
|
GetCircleFillAppStream(rcCenter, crBackground) +
|
|
GetCircleBorderAppStream(rcCenter, fBorderWidth, crBorder, crLeftTop,
|
|
crRightBottom, nBorderStyle, dsBorder);
|
|
} else {
|
|
csAP_N_ON =
|
|
GetRectFillAppStream(rcWindow, crBackground) +
|
|
GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
|
|
crRightBottom, nBorderStyle, dsBorder);
|
|
}
|
|
|
|
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(CFX_Color::kGray, 0);
|
|
crRightBottom = CFX_Color(CFX_Color::kGray, 1);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ByteString csAP_D_ON;
|
|
|
|
if (nStyle == CheckStyle::kCircle) {
|
|
CFX_Color crBK = crBackground - 0.25f;
|
|
if (nBorderStyle == BorderStyle::BEVELED) {
|
|
crLeftTop = crBackground - 0.25f;
|
|
crRightBottom = CFX_Color(CFX_Color::kGray, 1);
|
|
crBK = crBackground;
|
|
} else if (nBorderStyle == BorderStyle::INSET) {
|
|
crLeftTop = CFX_Color(CFX_Color::kGray, 0);
|
|
crRightBottom = CFX_Color(CFX_Color::kGray, 1);
|
|
}
|
|
|
|
csAP_D_ON =
|
|
GetCircleFillAppStream(rcCenter, crBK) +
|
|
GetCircleBorderAppStream(rcCenter, fBorderWidth, crBorder, crLeftTop,
|
|
crRightBottom, nBorderStyle, dsBorder);
|
|
} else {
|
|
csAP_D_ON =
|
|
GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
|
|
GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
|
|
crRightBottom, nBorderStyle, dsBorder);
|
|
}
|
|
|
|
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");
|
|
|
|
ByteString csAS = widget_->GetAppState();
|
|
if (csAS.IsEmpty())
|
|
widget_->SetAppState("Off");
|
|
}
|
|
|
|
void CPDFSDK_AppStream::SetAsComboBox(Optional<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();
|
|
|
|
// Font map must outlive |pEdit|.
|
|
CBA_FontMap font_map(widget_->GetPDFPage()->GetDocument(),
|
|
widget_->GetPDFAnnot()->GetAnnotDict());
|
|
|
|
auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
|
|
pEdit->EnableRefresh(false);
|
|
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.has_value()) {
|
|
pEdit->SetText(sValue.value());
|
|
} 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();
|
|
ByteString sEdit = GetEditAppStream(pEdit.get(), CFX_PointF(), true, 0);
|
|
if (sEdit.GetLength() > 0) {
|
|
sBody << "/Tx ";
|
|
AutoClosedCommand bmc(&sBody, kMarkedSequenceBeginOperator,
|
|
kMarkedSequenceEndOperator);
|
|
AutoClosedQCommand q(&sBody);
|
|
|
|
if (rcContent.Width() > rcEdit.Width() ||
|
|
rcContent.Height() > rcEdit.Height()) {
|
|
sBody << rcEdit.left << " " << rcEdit.bottom << " " << rcEdit.Width()
|
|
<< " " << rcEdit.Height() << " " << kAppendRectOperator << "\n"
|
|
<< kSetNonZeroWindingClipOperator << "\n"
|
|
<< kEndPathNoFillOrStrokeOperator << "\n";
|
|
}
|
|
|
|
CFX_Color crText = widget_->GetTextPWLColor();
|
|
AutoClosedCommand bt(&sBody, kTextBeginOperator, kTextEndOperator);
|
|
sBody << GetColorAppStream(crText, true) << sEdit;
|
|
}
|
|
|
|
sBody << GetDropButtonAppStream(rcButton);
|
|
Write("N",
|
|
GetBackgroundAppStream() + GetBorderAppStream() + ByteString(sBody),
|
|
ByteString());
|
|
}
|
|
|
|
void CPDFSDK_AppStream::SetAsListBox() {
|
|
CPDF_FormControl* pControl = widget_->GetFormControl();
|
|
CPDF_FormField* pField = pControl->GetField();
|
|
CFX_FloatRect rcClient = widget_->GetClientRect();
|
|
std::ostringstream sBody;
|
|
|
|
// Font map must outlive |pEdit|.
|
|
CBA_FontMap font_map(widget_->GetPDFPage()->GetDocument(),
|
|
widget_->GetPDFAnnot()->GetAnnotDict());
|
|
|
|
auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
|
|
pEdit->EnableRefresh(false);
|
|
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);
|
|
{
|
|
AutoClosedQCommand q(&sList);
|
|
sList << GetColorAppStream(CFX_Color(CFX_Color::kRGB, 0, 51.0f / 255.0f,
|
|
113.0f / 255.0f),
|
|
true)
|
|
<< rcItem.left << " " << rcItem.bottom << " " << rcItem.Width()
|
|
<< " " << rcItem.Height() << " " << kAppendRectOperator << " "
|
|
<< kFillOperator << "\n";
|
|
}
|
|
|
|
AutoClosedCommand bt(&sList, kTextBeginOperator, kTextEndOperator);
|
|
sList << GetColorAppStream(CFX_Color(CFX_Color::kGray, 1), true)
|
|
<< GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy), true, 0);
|
|
} else {
|
|
CFX_Color crText = widget_->GetTextPWLColor();
|
|
|
|
AutoClosedCommand bt(&sList, kTextBeginOperator, kTextEndOperator);
|
|
sList << GetColorAppStream(crText, true)
|
|
<< GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy), true, 0);
|
|
}
|
|
|
|
fy -= fItemHeight;
|
|
}
|
|
|
|
if (sList.tellp() > 0) {
|
|
sBody << "/Tx ";
|
|
AutoClosedCommand bmc(&sBody, kMarkedSequenceBeginOperator,
|
|
kMarkedSequenceEndOperator);
|
|
AutoClosedQCommand q(&sBody);
|
|
|
|
sBody << rcClient.left << " " << rcClient.bottom << " " << rcClient.Width()
|
|
<< " " << rcClient.Height() << " " << kAppendRectOperator << "\n"
|
|
<< kSetNonZeroWindingClipOperator << "\n"
|
|
<< kEndPathNoFillOrStrokeOperator << "\n"
|
|
<< sList.str();
|
|
}
|
|
Write("N",
|
|
GetBackgroundAppStream() + GetBorderAppStream() + ByteString(sBody),
|
|
ByteString());
|
|
}
|
|
|
|
void CPDFSDK_AppStream::SetAsTextField(Optional<WideString> sValue) {
|
|
CPDF_FormControl* pControl = widget_->GetFormControl();
|
|
CPDF_FormField* pField = pControl->GetField();
|
|
std::ostringstream sBody;
|
|
std::ostringstream sLines;
|
|
|
|
// Font map must outlive |pEdit|.
|
|
CBA_FontMap font_map(widget_->GetPDFPage()->GetDocument(),
|
|
widget_->GetPDFAnnot()->GetAnnotDict());
|
|
|
|
auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
|
|
pEdit->EnableRefresh(false);
|
|
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 & pdfium::form_flags::kTextMultiline;
|
|
if (bMultiLine) {
|
|
pEdit->SetMultiLine(true, true);
|
|
pEdit->SetAutoReturn(true, true);
|
|
} else {
|
|
pEdit->SetAlignmentV(1, true);
|
|
}
|
|
|
|
uint16_t subWord = 0;
|
|
if (dwFieldFlags & pdfium::form_flags::kTextPassword) {
|
|
subWord = '*';
|
|
pEdit->SetPasswordChar(subWord, true);
|
|
}
|
|
|
|
int nMaxLen = pField->GetMaxLen();
|
|
bool bCharArray = dwFieldFlags & pdfium::form_flags::kTextComb;
|
|
float fFontSize = widget_->GetFontSize();
|
|
|
|
#ifdef PDF_ENABLE_XFA
|
|
if (!sValue.has_value() && widget_->GetMixXFAWidget())
|
|
sValue = widget_->GetValue();
|
|
#endif // PDF_ENABLE_XFA
|
|
|
|
if (nMaxLen > 0) {
|
|
if (bCharArray) {
|
|
pEdit->SetCharArray(nMaxLen);
|
|
if (IsFloatZero(fFontSize)) {
|
|
fFontSize = CPWL_Edit::GetCharArrayAutoFontSize(
|
|
font_map.GetPDFFont(0).Get(), rcClient, nMaxLen);
|
|
}
|
|
} else {
|
|
if (sValue.has_value())
|
|
nMaxLen = sValue.value().GetLength();
|
|
pEdit->SetLimitChar(nMaxLen);
|
|
}
|
|
}
|
|
|
|
if (IsFloatZero(fFontSize))
|
|
pEdit->SetAutoFontSize(true, true);
|
|
else
|
|
pEdit->SetFontSize(fFontSize);
|
|
|
|
pEdit->Initialize();
|
|
pEdit->SetText(sValue.value_or(pField->GetValue()));
|
|
|
|
CFX_FloatRect rcContent = pEdit->GetContentRect();
|
|
ByteString sEdit =
|
|
GetEditAppStream(pEdit.get(), CFX_PointF(), !bCharArray, subWord);
|
|
|
|
if (sEdit.GetLength() > 0) {
|
|
sBody << "/Tx ";
|
|
AutoClosedCommand bmc(&sBody, kMarkedSequenceBeginOperator,
|
|
kMarkedSequenceEndOperator);
|
|
AutoClosedQCommand q(&sBody);
|
|
|
|
if (rcContent.Width() > rcClient.Width() ||
|
|
rcContent.Height() > rcClient.Height()) {
|
|
sBody << rcClient.left << " " << rcClient.bottom << " "
|
|
<< rcClient.Width() << " " << rcClient.Height() << " "
|
|
<< kAppendRectOperator << "\n"
|
|
<< kSetNonZeroWindingClipOperator << "\n"
|
|
<< kEndPathNoFillOrStrokeOperator << "\n";
|
|
}
|
|
CFX_Color crText = widget_->GetTextPWLColor();
|
|
|
|
AutoClosedCommand bt(&sBody, kTextBeginOperator, kTextEndOperator);
|
|
sBody << GetColorAppStream(crText, true) << sEdit;
|
|
}
|
|
|
|
if (bCharArray) {
|
|
switch (widget_->GetBorderStyle()) {
|
|
case BorderStyle::SOLID: {
|
|
ByteString sColor =
|
|
GetColorAppStream(widget_->GetBorderPWLColor(), false);
|
|
if (sColor.GetLength() > 0) {
|
|
AutoClosedQCommand q(&sLines);
|
|
sLines << widget_->GetBorderWidth() << " " << kSetLineWidthOperator
|
|
<< "\n"
|
|
<< GetColorAppStream(widget_->GetBorderPWLColor(), false)
|
|
<< " 2 " << kSetLineCapStyleOperator << " 0 "
|
|
<< kSetLineJoinStyleOperator << "\n";
|
|
|
|
for (int32_t i = 1; i < nMaxLen; ++i) {
|
|
sLines << rcClient.left +
|
|
((rcClient.right - rcClient.left) / nMaxLen) * i
|
|
<< " " << rcClient.bottom << " " << kMoveToOperator << "\n"
|
|
<< rcClient.left +
|
|
((rcClient.right - rcClient.left) / nMaxLen) * i
|
|
<< " " << rcClient.top << " " << kLineToOperator << " "
|
|
<< kStrokeOperator << "\n";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case BorderStyle::DASH: {
|
|
ByteString sColor =
|
|
GetColorAppStream(widget_->GetBorderPWLColor(), false);
|
|
if (sColor.GetLength() > 0) {
|
|
CPWL_Dash dsBorder = CPWL_Dash(3, 3, 0);
|
|
AutoClosedQCommand q(&sLines);
|
|
sLines << widget_->GetBorderWidth() << " " << kSetLineWidthOperator
|
|
<< "\n"
|
|
<< GetColorAppStream(widget_->GetBorderPWLColor(), false)
|
|
<< "[" << dsBorder.nDash << " " << dsBorder.nGap << "] "
|
|
<< dsBorder.nPhase << " " << kSetDashOperator << "\n";
|
|
|
|
for (int32_t i = 1; i < nMaxLen; ++i) {
|
|
sLines << rcClient.left +
|
|
((rcClient.right - rcClient.left) / nMaxLen) * i
|
|
<< " " << rcClient.bottom << " " << kMoveToOperator << "\n"
|
|
<< rcClient.left +
|
|
((rcClient.right - rcClient.left) / nMaxLen) * i
|
|
<< " " << rcClient.top << " " << kLineToOperator << " "
|
|
<< kStrokeOperator << "\n";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
Write("N",
|
|
GetBackgroundAppStream() + GetBorderAppStream() + ByteString(sLines) +
|
|
ByteString(sBody),
|
|
ByteString());
|
|
}
|
|
|
|
void CPDFSDK_AppStream::AddImage(const ByteString& sAPType,
|
|
CPDF_Stream* pImage) {
|
|
CPDF_Stream* pStream = dict_->GetStreamFor(sAPType);
|
|
CPDF_Dictionary* pStreamDict = pStream->GetDict();
|
|
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 CPDFSDK_AppStream::Write(const ByteString& sAPType,
|
|
const ByteString& sContents,
|
|
const 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 =
|
|
widget_->GetPDFAnnot()->GetDocument()->New<CPDF_Dictionary>();
|
|
pStreamDict = pNewDict.Get();
|
|
pStreamDict->SetNewFor<CPDF_Name>("Type", "XObject");
|
|
pStreamDict->SetNewFor<CPDF_Name>("Subtype", "Form");
|
|
pStreamDict->SetNewFor<CPDF_Number>("FormType", 1);
|
|
pStream->InitStream({}, std::move(pNewDict));
|
|
}
|
|
pStreamDict->SetMatrixFor("Matrix", widget_->GetMatrix());
|
|
pStreamDict->SetRectFor("BBox", widget_->GetRotatedRect());
|
|
pStream->SetDataAndRemoveFilter(sContents.raw_span());
|
|
}
|
|
|
|
void CPDFSDK_AppStream::Remove(const ByteString& sAPType) {
|
|
dict_->RemoveFor(sAPType);
|
|
}
|
|
|
|
ByteString CPDFSDK_AppStream::GetBackgroundAppStream() const {
|
|
CFX_Color crBackground = widget_->GetFillPWLColor();
|
|
if (crBackground.nColorType != CFX_Color::kTransparent)
|
|
return GetRectFillAppStream(widget_->GetRotatedRect(), crBackground);
|
|
|
|
return ByteString();
|
|
}
|
|
|
|
ByteString CPDFSDK_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(CFX_Color::kGray, 1);
|
|
crRightBottom = crBackground / 2.0f;
|
|
break;
|
|
case BorderStyle::INSET:
|
|
fBorderWidth *= 2;
|
|
crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
|
|
crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
|
|
crRightBottom, nBorderStyle, dsBorder);
|
|
}
|