1// Copyright 2016 PDFium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7#include "core/fpdfdoc/cpvt_generateap.h" 8 9#include <algorithm> 10#include <memory> 11#include <utility> 12 13#include "core/fpdfapi/font/cpdf_font.h" 14#include "core/fpdfapi/parser/cpdf_boolean.h" 15#include "core/fpdfapi/parser/cpdf_dictionary.h" 16#include "core/fpdfapi/parser/cpdf_document.h" 17#include "core/fpdfapi/parser/cpdf_name.h" 18#include "core/fpdfapi/parser/cpdf_number.h" 19#include "core/fpdfapi/parser/cpdf_reference.h" 20#include "core/fpdfapi/parser/cpdf_simple_parser.h" 21#include "core/fpdfapi/parser/cpdf_stream.h" 22#include "core/fpdfapi/parser/cpdf_string.h" 23#include "core/fpdfapi/parser/fpdf_parser_decode.h" 24#include "core/fpdfdoc/cpdf_annot.h" 25#include "core/fpdfdoc/cpdf_formfield.h" 26#include "core/fpdfdoc/cpvt_color.h" 27#include "core/fpdfdoc/cpvt_fontmap.h" 28#include "core/fpdfdoc/cpvt_word.h" 29#include "third_party/base/ptr_util.h" 30 31namespace { 32 33bool GenerateWidgetAP(CPDF_Document* pDoc, 34 CPDF_Dictionary* pAnnotDict, 35 const int32_t& nWidgetType) { 36 CPDF_Dictionary* pFormDict = nullptr; 37 if (CPDF_Dictionary* pRootDict = pDoc->GetRoot()) 38 pFormDict = pRootDict->GetDictFor("AcroForm"); 39 if (!pFormDict) 40 return false; 41 42 CFX_ByteString DA; 43 if (CPDF_Object* pDAObj = FPDF_GetFieldAttr(pAnnotDict, "DA")) 44 DA = pDAObj->GetString(); 45 if (DA.IsEmpty()) 46 DA = pFormDict->GetStringFor("DA"); 47 if (DA.IsEmpty()) 48 return false; 49 50 CPDF_SimpleParser syntax(DA.AsStringC()); 51 syntax.FindTagParamFromStart("Tf", 2); 52 CFX_ByteString sFontName(syntax.GetWord()); 53 sFontName = PDF_NameDecode(sFontName); 54 if (sFontName.IsEmpty()) 55 return false; 56 57 FX_FLOAT fFontSize = FX_atof(syntax.GetWord()); 58 CPVT_Color crText = CPVT_Color::ParseColor(DA); 59 CPDF_Dictionary* pDRDict = pFormDict->GetDictFor("DR"); 60 if (!pDRDict) 61 return false; 62 63 CPDF_Dictionary* pDRFontDict = pDRDict->GetDictFor("Font"); 64 if (!pDRFontDict) 65 return false; 66 67 CPDF_Dictionary* pFontDict = pDRFontDict->GetDictFor(sFontName.Mid(1)); 68 if (!pFontDict) { 69 pFontDict = pDoc->NewIndirect<CPDF_Dictionary>(); 70 pFontDict->SetNewFor<CPDF_Name>("Type", "Font"); 71 pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1"); 72 pFontDict->SetNewFor<CPDF_Name>("BaseFont", "Helvetica"); 73 pFontDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding"); 74 pDRFontDict->SetNewFor<CPDF_Reference>(sFontName.Mid(1), pDoc, 75 pFontDict->GetObjNum()); 76 } 77 CPDF_Font* pDefFont = pDoc->LoadFont(pFontDict); 78 if (!pDefFont) 79 return false; 80 81 CFX_FloatRect rcAnnot = pAnnotDict->GetRectFor("Rect"); 82 int32_t nRotate = 0; 83 if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK")) 84 nRotate = pMKDict->GetIntegerFor("R"); 85 86 CFX_FloatRect rcBBox; 87 CFX_Matrix matrix; 88 switch (nRotate % 360) { 89 case 0: 90 rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left, 91 rcAnnot.top - rcAnnot.bottom); 92 break; 93 case 90: 94 matrix = CFX_Matrix(0, 1, -1, 0, rcAnnot.right - rcAnnot.left, 0); 95 rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom, 96 rcAnnot.right - rcAnnot.left); 97 break; 98 case 180: 99 matrix = CFX_Matrix(-1, 0, 0, -1, rcAnnot.right - rcAnnot.left, 100 rcAnnot.top - rcAnnot.bottom); 101 rcBBox = CFX_FloatRect(0, 0, rcAnnot.right - rcAnnot.left, 102 rcAnnot.top - rcAnnot.bottom); 103 break; 104 case 270: 105 matrix = CFX_Matrix(0, -1, 1, 0, 0, rcAnnot.top - rcAnnot.bottom); 106 rcBBox = CFX_FloatRect(0, 0, rcAnnot.top - rcAnnot.bottom, 107 rcAnnot.right - rcAnnot.left); 108 break; 109 } 110 111 BorderStyle nBorderStyle = BorderStyle::SOLID; 112 FX_FLOAT fBorderWidth = 1; 113 CPVT_Dash dsBorder(3, 0, 0); 114 CPVT_Color crLeftTop, crRightBottom; 115 if (CPDF_Dictionary* pBSDict = pAnnotDict->GetDictFor("BS")) { 116 if (pBSDict->KeyExist("W")) 117 fBorderWidth = pBSDict->GetNumberFor("W"); 118 119 if (CPDF_Array* pArray = pBSDict->GetArrayFor("D")) { 120 dsBorder = CPVT_Dash(pArray->GetIntegerAt(0), pArray->GetIntegerAt(1), 121 pArray->GetIntegerAt(2)); 122 } 123 switch (pBSDict->GetStringFor("S").GetAt(0)) { 124 case 'S': 125 nBorderStyle = BorderStyle::SOLID; 126 break; 127 case 'D': 128 nBorderStyle = BorderStyle::DASH; 129 break; 130 case 'B': 131 nBorderStyle = BorderStyle::BEVELED; 132 fBorderWidth *= 2; 133 crLeftTop = CPVT_Color(CPVT_Color::kGray, 1); 134 crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.5); 135 break; 136 case 'I': 137 nBorderStyle = BorderStyle::INSET; 138 fBorderWidth *= 2; 139 crLeftTop = CPVT_Color(CPVT_Color::kGray, 0.5); 140 crRightBottom = CPVT_Color(CPVT_Color::kGray, 0.75); 141 break; 142 case 'U': 143 nBorderStyle = BorderStyle::UNDERLINE; 144 break; 145 } 146 } 147 CPVT_Color crBorder, crBG; 148 if (CPDF_Dictionary* pMKDict = pAnnotDict->GetDictFor("MK")) { 149 if (CPDF_Array* pArray = pMKDict->GetArrayFor("BC")) 150 crBorder = CPVT_Color::ParseColor(*pArray); 151 if (CPDF_Array* pArray = pMKDict->GetArrayFor("BG")) 152 crBG = CPVT_Color::ParseColor(*pArray); 153 } 154 CFX_ByteTextBuf sAppStream; 155 CFX_ByteString sBG = 156 CPVT_GenerateAP::GenerateColorAP(crBG, PaintOperation::FILL); 157 if (sBG.GetLength() > 0) { 158 sAppStream << "q\n" << sBG << rcBBox.left << " " << rcBBox.bottom << " " 159 << rcBBox.Width() << " " << rcBBox.Height() << " re f\n" 160 << "Q\n"; 161 } 162 CFX_ByteString sBorderStream = CPVT_GenerateAP::GenerateBorderAP( 163 rcBBox, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, 164 dsBorder); 165 if (sBorderStream.GetLength() > 0) 166 sAppStream << "q\n" << sBorderStream << "Q\n"; 167 168 CFX_FloatRect rcBody = 169 CFX_FloatRect(rcBBox.left + fBorderWidth, rcBBox.bottom + fBorderWidth, 170 rcBBox.right - fBorderWidth, rcBBox.top - fBorderWidth); 171 rcBody.Normalize(); 172 173 CPDF_Dictionary* pAPDict = pAnnotDict->GetDictFor("AP"); 174 if (!pAPDict) 175 pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP"); 176 177 CPDF_Stream* pNormalStream = pAPDict->GetStreamFor("N"); 178 if (!pNormalStream) { 179 pNormalStream = pDoc->NewIndirect<CPDF_Stream>(); 180 pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum()); 181 } 182 CPDF_Dictionary* pStreamDict = pNormalStream->GetDict(); 183 if (pStreamDict) { 184 pStreamDict->SetMatrixFor("Matrix", matrix); 185 pStreamDict->SetRectFor("BBox", rcBBox); 186 CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources"); 187 if (pStreamResList) { 188 CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictFor("Font"); 189 if (!pStreamResFontList) 190 pStreamResFontList = pStreamResList->SetNewFor<CPDF_Dictionary>("Font"); 191 if (!pStreamResFontList->KeyExist(sFontName)) { 192 pStreamResFontList->SetNewFor<CPDF_Reference>(sFontName, pDoc, 193 pFontDict->GetObjNum()); 194 } 195 } else { 196 pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone()); 197 pStreamResList = pStreamDict->GetDictFor("Resources"); 198 } 199 } 200 switch (nWidgetType) { 201 case 0: { 202 CFX_WideString swValue = 203 FPDF_GetFieldAttr(pAnnotDict, "V") 204 ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText() 205 : CFX_WideString(); 206 int32_t nAlign = FPDF_GetFieldAttr(pAnnotDict, "Q") 207 ? FPDF_GetFieldAttr(pAnnotDict, "Q")->GetInteger() 208 : 0; 209 uint32_t dwFlags = FPDF_GetFieldAttr(pAnnotDict, "Ff") 210 ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger() 211 : 0; 212 uint32_t dwMaxLen = 213 FPDF_GetFieldAttr(pAnnotDict, "MaxLen") 214 ? FPDF_GetFieldAttr(pAnnotDict, "MaxLen")->GetInteger() 215 : 0; 216 CPVT_FontMap map( 217 pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr, 218 pDefFont, sFontName.Right(sFontName.GetLength() - 1)); 219 CPDF_VariableText::Provider prd(&map); 220 CPDF_VariableText vt; 221 vt.SetProvider(&prd); 222 vt.SetPlateRect(rcBody); 223 vt.SetAlignment(nAlign); 224 if (IsFloatZero(fFontSize)) 225 vt.SetAutoFontSize(true); 226 else 227 vt.SetFontSize(fFontSize); 228 229 bool bMultiLine = (dwFlags >> 12) & 1; 230 if (bMultiLine) { 231 vt.SetMultiLine(true); 232 vt.SetAutoReturn(true); 233 } 234 uint16_t subWord = 0; 235 if ((dwFlags >> 13) & 1) { 236 subWord = '*'; 237 vt.SetPasswordChar(subWord); 238 } 239 bool bCharArray = (dwFlags >> 24) & 1; 240 if (bCharArray) 241 vt.SetCharArray(dwMaxLen); 242 else 243 vt.SetLimitChar(dwMaxLen); 244 245 vt.Initialize(); 246 vt.SetText(swValue); 247 vt.RearrangeAll(); 248 CFX_FloatRect rcContent = vt.GetContentRect(); 249 CFX_PointF ptOffset; 250 if (!bMultiLine) { 251 ptOffset = 252 CFX_PointF(0.0f, (rcContent.Height() - rcBody.Height()) / 2.0f); 253 } 254 CFX_ByteString sBody = CPVT_GenerateAP::GenerateEditAP( 255 &map, vt.GetIterator(), ptOffset, !bCharArray, subWord); 256 if (sBody.GetLength() > 0) { 257 sAppStream << "/Tx BMC\n" 258 << "q\n"; 259 if (rcContent.Width() > rcBody.Width() || 260 rcContent.Height() > rcBody.Height()) { 261 sAppStream << rcBody.left << " " << rcBody.bottom << " " 262 << rcBody.Width() << " " << rcBody.Height() 263 << " re\nW\nn\n"; 264 } 265 sAppStream << "BT\n" 266 << CPVT_GenerateAP::GenerateColorAP(crText, 267 PaintOperation::FILL) 268 << sBody << "ET\n" 269 << "Q\nEMC\n"; 270 } 271 } break; 272 case 1: { 273 CFX_WideString swValue = 274 FPDF_GetFieldAttr(pAnnotDict, "V") 275 ? FPDF_GetFieldAttr(pAnnotDict, "V")->GetUnicodeText() 276 : CFX_WideString(); 277 CPVT_FontMap map( 278 pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr, 279 pDefFont, sFontName.Right(sFontName.GetLength() - 1)); 280 CPDF_VariableText::Provider prd(&map); 281 CPDF_VariableText vt; 282 vt.SetProvider(&prd); 283 CFX_FloatRect rcButton = rcBody; 284 rcButton.left = rcButton.right - 13; 285 rcButton.Normalize(); 286 CFX_FloatRect rcEdit = rcBody; 287 rcEdit.right = rcButton.left; 288 rcEdit.Normalize(); 289 vt.SetPlateRect(rcEdit); 290 if (IsFloatZero(fFontSize)) 291 vt.SetAutoFontSize(true); 292 else 293 vt.SetFontSize(fFontSize); 294 295 vt.Initialize(); 296 vt.SetText(swValue); 297 vt.RearrangeAll(); 298 CFX_FloatRect rcContent = vt.GetContentRect(); 299 CFX_PointF ptOffset = 300 CFX_PointF(0.0f, (rcContent.Height() - rcEdit.Height()) / 2.0f); 301 CFX_ByteString sEdit = CPVT_GenerateAP::GenerateEditAP( 302 &map, vt.GetIterator(), ptOffset, true, 0); 303 if (sEdit.GetLength() > 0) { 304 sAppStream << "/Tx BMC\n" 305 << "q\n"; 306 sAppStream << rcEdit.left << " " << rcEdit.bottom << " " 307 << rcEdit.Width() << " " << rcEdit.Height() << " re\nW\nn\n"; 308 sAppStream << "BT\n" 309 << CPVT_GenerateAP::GenerateColorAP(crText, 310 PaintOperation::FILL) 311 << sEdit << "ET\n" 312 << "Q\nEMC\n"; 313 } 314 CFX_ByteString sButton = CPVT_GenerateAP::GenerateColorAP( 315 CPVT_Color(CPVT_Color::kRGB, 220.0f / 255.0f, 220.0f / 255.0f, 316 220.0f / 255.0f), 317 PaintOperation::FILL); 318 if (sButton.GetLength() > 0 && !rcButton.IsEmpty()) { 319 sAppStream << "q\n" << sButton; 320 sAppStream << rcButton.left << " " << rcButton.bottom << " " 321 << rcButton.Width() << " " << rcButton.Height() << " re f\n"; 322 sAppStream << "Q\n"; 323 CFX_ByteString sButtonBorder = CPVT_GenerateAP::GenerateBorderAP( 324 rcButton, 2, CPVT_Color(CPVT_Color::kGray, 0), 325 CPVT_Color(CPVT_Color::kGray, 1), 326 CPVT_Color(CPVT_Color::kGray, 0.5), BorderStyle::BEVELED, 327 CPVT_Dash(3, 0, 0)); 328 if (sButtonBorder.GetLength() > 0) 329 sAppStream << "q\n" << sButtonBorder << "Q\n"; 330 331 CFX_PointF ptCenter = CFX_PointF((rcButton.left + rcButton.right) / 2, 332 (rcButton.top + rcButton.bottom) / 2); 333 if (IsFloatBigger(rcButton.Width(), 6) && 334 IsFloatBigger(rcButton.Height(), 6)) { 335 sAppStream << "q\n" 336 << " 0 g\n"; 337 sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n"; 338 sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n"; 339 sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n"; 340 sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n"; 341 sAppStream << sButton << "Q\n"; 342 } 343 } 344 } break; 345 case 2: { 346 CPVT_FontMap map( 347 pDoc, pStreamDict ? pStreamDict->GetDictFor("Resources") : nullptr, 348 pDefFont, sFontName.Right(sFontName.GetLength() - 1)); 349 CPDF_VariableText::Provider prd(&map); 350 CPDF_Array* pOpts = ToArray(FPDF_GetFieldAttr(pAnnotDict, "Opt")); 351 CPDF_Array* pSels = ToArray(FPDF_GetFieldAttr(pAnnotDict, "I")); 352 CPDF_Object* pTi = FPDF_GetFieldAttr(pAnnotDict, "TI"); 353 int32_t nTop = pTi ? pTi->GetInteger() : 0; 354 CFX_ByteTextBuf sBody; 355 if (pOpts) { 356 FX_FLOAT fy = rcBody.top; 357 for (size_t i = nTop, sz = pOpts->GetCount(); i < sz; i++) { 358 if (IsFloatSmaller(fy, rcBody.bottom)) 359 break; 360 361 if (CPDF_Object* pOpt = pOpts->GetDirectObjectAt(i)) { 362 CFX_WideString swItem; 363 if (pOpt->IsString()) 364 swItem = pOpt->GetUnicodeText(); 365 else if (CPDF_Array* pArray = pOpt->AsArray()) 366 swItem = pArray->GetDirectObjectAt(1)->GetUnicodeText(); 367 368 bool bSelected = false; 369 if (pSels) { 370 for (size_t s = 0, ssz = pSels->GetCount(); s < ssz; s++) { 371 int value = pSels->GetIntegerAt(s); 372 if (value >= 0 && i == static_cast<size_t>(value)) { 373 bSelected = true; 374 break; 375 } 376 } 377 } 378 CPDF_VariableText vt; 379 vt.SetProvider(&prd); 380 vt.SetPlateRect( 381 CFX_FloatRect(rcBody.left, 0.0f, rcBody.right, 0.0f)); 382 vt.SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize); 383 384 vt.Initialize(); 385 vt.SetText(swItem); 386 vt.RearrangeAll(); 387 FX_FLOAT fItemHeight = vt.GetContentRect().Height(); 388 if (bSelected) { 389 CFX_FloatRect rcItem = CFX_FloatRect( 390 rcBody.left, fy - fItemHeight, rcBody.right, fy); 391 sBody << "q\n" 392 << CPVT_GenerateAP::GenerateColorAP( 393 CPVT_Color(CPVT_Color::kRGB, 0, 51.0f / 255.0f, 394 113.0f / 255.0f), 395 PaintOperation::FILL) 396 << rcItem.left << " " << rcItem.bottom << " " 397 << rcItem.Width() << " " << rcItem.Height() << " re f\n" 398 << "Q\n"; 399 sBody << "BT\n" 400 << CPVT_GenerateAP::GenerateColorAP( 401 CPVT_Color(CPVT_Color::kGray, 1), 402 PaintOperation::FILL) 403 << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(), 404 CFX_PointF(0.0f, fy), 405 true, 0) 406 << "ET\n"; 407 } else { 408 sBody << "BT\n" 409 << CPVT_GenerateAP::GenerateColorAP(crText, 410 PaintOperation::FILL) 411 << CPVT_GenerateAP::GenerateEditAP(&map, vt.GetIterator(), 412 CFX_PointF(0.0f, fy), 413 true, 0) 414 << "ET\n"; 415 } 416 fy -= fItemHeight; 417 } 418 } 419 } 420 if (sBody.GetSize() > 0) { 421 sAppStream << "/Tx BMC\nq\n" 422 << rcBody.left << " " << rcBody.bottom << " " 423 << rcBody.Width() << " " << rcBody.Height() << " re\nW\nn\n" 424 << sBody.AsStringC() << "Q\nEMC\n"; 425 } 426 } break; 427 } 428 if (pNormalStream) { 429 pNormalStream->SetData(sAppStream.GetBuffer(), sAppStream.GetSize()); 430 pStreamDict = pNormalStream->GetDict(); 431 if (pStreamDict) { 432 pStreamDict->SetMatrixFor("Matrix", matrix); 433 pStreamDict->SetRectFor("BBox", rcBBox); 434 CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources"); 435 if (pStreamResList) { 436 CPDF_Dictionary* pStreamResFontList = 437 pStreamResList->GetDictFor("Font"); 438 if (!pStreamResFontList) { 439 pStreamResFontList = 440 pStreamResList->SetNewFor<CPDF_Dictionary>("Font"); 441 } 442 if (!pStreamResFontList->KeyExist(sFontName)) { 443 pStreamResFontList->SetNewFor<CPDF_Reference>(sFontName, pDoc, 444 pFontDict->GetObjNum()); 445 } 446 } else { 447 pStreamDict->SetFor("Resources", pFormDict->GetDictFor("DR")->Clone()); 448 pStreamResList = pStreamDict->GetDictFor("Resources"); 449 } 450 } 451 } 452 return true; 453} 454 455CFX_ByteString GetColorStringWithDefault(CPDF_Array* pColor, 456 const CPVT_Color& crDefaultColor, 457 PaintOperation nOperation) { 458 if (pColor) { 459 CPVT_Color color = CPVT_Color::ParseColor(*pColor); 460 return CPVT_GenerateAP::GenerateColorAP(color, nOperation); 461 } 462 463 return CPVT_GenerateAP::GenerateColorAP(crDefaultColor, nOperation); 464} 465 466FX_FLOAT GetBorderWidth(const CPDF_Dictionary& pAnnotDict) { 467 if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictFor("BS")) { 468 if (pBorderStyleDict->KeyExist("W")) 469 return pBorderStyleDict->GetNumberFor("W"); 470 } 471 472 if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayFor("Border")) { 473 if (pBorderArray->GetCount() > 2) 474 return pBorderArray->GetNumberAt(2); 475 } 476 477 return 1; 478} 479 480CPDF_Array* GetDashArray(const CPDF_Dictionary& pAnnotDict) { 481 if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictFor("BS")) { 482 if (pBorderStyleDict->GetStringFor("S") == "D") 483 return pBorderStyleDict->GetArrayFor("D"); 484 } 485 486 if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayFor("Border")) { 487 if (pBorderArray->GetCount() == 4) 488 return pBorderArray->GetArrayAt(3); 489 } 490 491 return nullptr; 492} 493 494CFX_ByteString GetDashPatternString(const CPDF_Dictionary& pAnnotDict) { 495 CPDF_Array* pDashArray = GetDashArray(pAnnotDict); 496 if (!pDashArray || pDashArray->IsEmpty()) 497 return CFX_ByteString(); 498 499 // Support maximum of ten elements in the dash array. 500 size_t pDashArrayCount = std::min<size_t>(pDashArray->GetCount(), 10); 501 CFX_ByteTextBuf sDashStream; 502 503 sDashStream << "["; 504 for (size_t i = 0; i < pDashArrayCount; ++i) 505 sDashStream << pDashArray->GetNumberAt(i) << " "; 506 sDashStream << "] 0 d\n"; 507 508 return sDashStream.MakeString(); 509} 510 511CFX_ByteString GetPopupContentsString(CPDF_Document* pDoc, 512 const CPDF_Dictionary& pAnnotDict, 513 CPDF_Font* pDefFont, 514 const CFX_ByteString& sFontName) { 515 CFX_WideString swValue(pAnnotDict.GetUnicodeTextFor("T")); 516 swValue += L'\n'; 517 swValue += pAnnotDict.GetUnicodeTextFor("Contents"); 518 CPVT_FontMap map(pDoc, nullptr, pDefFont, sFontName); 519 520 CPDF_VariableText::Provider prd(&map); 521 CPDF_VariableText vt; 522 vt.SetProvider(&prd); 523 vt.SetPlateRect(pAnnotDict.GetRectFor("Rect")); 524 vt.SetFontSize(12); 525 vt.SetAutoReturn(true); 526 vt.SetMultiLine(true); 527 528 vt.Initialize(); 529 vt.SetText(swValue); 530 vt.RearrangeAll(); 531 CFX_PointF ptOffset(3.0f, -3.0f); 532 CFX_ByteString sContent = CPVT_GenerateAP::GenerateEditAP( 533 &map, vt.GetIterator(), ptOffset, false, 0); 534 535 if (sContent.IsEmpty()) 536 return CFX_ByteString(); 537 538 CFX_ByteTextBuf sAppStream; 539 sAppStream << "BT\n" 540 << CPVT_GenerateAP::GenerateColorAP( 541 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::FILL) 542 << sContent << "ET\n" 543 << "Q\n"; 544 return sAppStream.MakeString(); 545} 546 547std::unique_ptr<CPDF_Dictionary> GenerateExtGStateDict( 548 const CPDF_Dictionary& pAnnotDict, 549 const CFX_ByteString& sExtGSDictName, 550 const CFX_ByteString& sBlendMode) { 551 auto pGSDict = 552 pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool()); 553 pGSDict->SetNewFor<CPDF_String>("Type", "ExtGState", false); 554 555 FX_FLOAT fOpacity = 556 pAnnotDict.KeyExist("CA") ? pAnnotDict.GetNumberFor("CA") : 1; 557 pGSDict->SetNewFor<CPDF_Number>("CA", fOpacity); 558 pGSDict->SetNewFor<CPDF_Number>("ca", fOpacity); 559 pGSDict->SetNewFor<CPDF_Boolean>("AIS", false); 560 pGSDict->SetNewFor<CPDF_String>("BM", sBlendMode, false); 561 562 auto pExtGStateDict = 563 pdfium::MakeUnique<CPDF_Dictionary>(pAnnotDict.GetByteStringPool()); 564 pExtGStateDict->SetFor(sExtGSDictName, std::move(pGSDict)); 565 return pExtGStateDict; 566} 567 568std::unique_ptr<CPDF_Dictionary> GenerateResourceFontDict( 569 CPDF_Document* pDoc, 570 const CFX_ByteString& sFontDictName) { 571 CPDF_Dictionary* pFontDict = pDoc->NewIndirect<CPDF_Dictionary>(); 572 pFontDict->SetNewFor<CPDF_Name>("Type", "Font"); 573 pFontDict->SetNewFor<CPDF_Name>("Subtype", "Type1"); 574 pFontDict->SetNewFor<CPDF_Name>("BaseFont", "Helvetica"); 575 pFontDict->SetNewFor<CPDF_Name>("Encoding", "WinAnsiEncoding"); 576 577 auto pResourceFontDict = 578 pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool()); 579 pResourceFontDict->SetNewFor<CPDF_Reference>(sFontDictName, pDoc, 580 pFontDict->GetObjNum()); 581 return pResourceFontDict; 582} 583 584std::unique_ptr<CPDF_Dictionary> GenerateResourceDict( 585 CPDF_Document* pDoc, 586 std::unique_ptr<CPDF_Dictionary> pExtGStateDict, 587 std::unique_ptr<CPDF_Dictionary> pResourceFontDict) { 588 auto pResourceDict = 589 pdfium::MakeUnique<CPDF_Dictionary>(pDoc->GetByteStringPool()); 590 if (pExtGStateDict) 591 pResourceDict->SetFor("ExtGState", std::move(pExtGStateDict)); 592 if (pResourceFontDict) 593 pResourceDict->SetFor("Font", std::move(pResourceFontDict)); 594 return pResourceDict; 595} 596 597void GenerateAndSetAPDict(CPDF_Document* pDoc, 598 CPDF_Dictionary* pAnnotDict, 599 const CFX_ByteTextBuf& sAppStream, 600 std::unique_ptr<CPDF_Dictionary> pResourceDict, 601 bool bIsTextMarkupAnnotation) { 602 CPDF_Stream* pNormalStream = pDoc->NewIndirect<CPDF_Stream>(); 603 pNormalStream->SetData(sAppStream.GetBuffer(), sAppStream.GetSize()); 604 605 CPDF_Dictionary* pAPDict = pAnnotDict->SetNewFor<CPDF_Dictionary>("AP"); 606 pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum()); 607 608 CPDF_Dictionary* pStreamDict = pNormalStream->GetDict(); 609 pStreamDict->SetNewFor<CPDF_Number>("FormType", 1); 610 pStreamDict->SetNewFor<CPDF_String>("Subtype", "Form", false); 611 pStreamDict->SetMatrixFor("Matrix", CFX_Matrix()); 612 613 CFX_FloatRect rect = bIsTextMarkupAnnotation 614 ? CPDF_Annot::RectFromQuadPoints(pAnnotDict) 615 : pAnnotDict->GetRectFor("Rect"); 616 pStreamDict->SetRectFor("BBox", rect); 617 pStreamDict->SetFor("Resources", std::move(pResourceDict)); 618} 619 620CFX_ByteString GetPaintOperatorString(bool bIsStrokeRect, bool bIsFillRect) { 621 if (bIsStrokeRect) 622 return bIsFillRect ? "b" : "s"; 623 return bIsFillRect ? "f" : "n"; 624} 625 626CFX_ByteString GenerateTextSymbolAP(const CFX_FloatRect& rect) { 627 CFX_ByteTextBuf sAppStream; 628 sAppStream << CPVT_GenerateAP::GenerateColorAP( 629 CPVT_Color(CPVT_Color::kRGB, 1, 1, 0), PaintOperation::FILL); 630 sAppStream << CPVT_GenerateAP::GenerateColorAP( 631 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), PaintOperation::STROKE); 632 633 const FX_FLOAT fBorderWidth = 1; 634 sAppStream << fBorderWidth << " w\n"; 635 636 const FX_FLOAT fHalfWidth = fBorderWidth / 2; 637 const FX_FLOAT fTipDelta = 4; 638 639 CFX_FloatRect outerRect1 = rect; 640 outerRect1.Deflate(fHalfWidth, fHalfWidth); 641 outerRect1.bottom += fTipDelta; 642 643 CFX_FloatRect outerRect2 = outerRect1; 644 outerRect2.left += fTipDelta; 645 outerRect2.right = outerRect2.left + fTipDelta; 646 outerRect2.top = outerRect2.bottom - fTipDelta; 647 FX_FLOAT outerRect2Middle = (outerRect2.left + outerRect2.right) / 2; 648 649 // Draw outer boxes. 650 sAppStream << outerRect1.left << " " << outerRect1.bottom << " m\n" 651 << outerRect1.left << " " << outerRect1.top << " l\n" 652 << outerRect1.right << " " << outerRect1.top << " l\n" 653 << outerRect1.right << " " << outerRect1.bottom << " l\n" 654 << outerRect2.right << " " << outerRect2.bottom << " l\n" 655 << outerRect2Middle << " " << outerRect2.top << " l\n" 656 << outerRect2.left << " " << outerRect2.bottom << " l\n" 657 << outerRect1.left << " " << outerRect1.bottom << " l\n"; 658 659 // Draw inner lines. 660 CFX_FloatRect lineRect = outerRect1; 661 const FX_FLOAT fXDelta = 2; 662 const FX_FLOAT fYDelta = (lineRect.top - lineRect.bottom) / 4; 663 664 lineRect.left += fXDelta; 665 lineRect.right -= fXDelta; 666 for (int i = 0; i < 3; ++i) { 667 lineRect.top -= fYDelta; 668 sAppStream << lineRect.left << " " << lineRect.top << " m\n" 669 << lineRect.right << " " << lineRect.top << " l\n"; 670 } 671 sAppStream << "B*\n"; 672 673 return sAppStream.MakeString(); 674} 675 676} // namespace 677 678bool FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { 679 if (!pAnnotDict || pAnnotDict->GetStringFor("Subtype") != "Widget") 680 return false; 681 682 CPDF_Object* pFieldTypeObj = FPDF_GetFieldAttr(pAnnotDict, "FT"); 683 if (!pFieldTypeObj) 684 return false; 685 686 CFX_ByteString field_type = pFieldTypeObj->GetString(); 687 if (field_type == "Tx") 688 return CPVT_GenerateAP::GenerateTextFieldAP(pDoc, pAnnotDict); 689 690 CPDF_Object* pFieldFlagsObj = FPDF_GetFieldAttr(pAnnotDict, "Ff"); 691 uint32_t flags = pFieldFlagsObj ? pFieldFlagsObj->GetInteger() : 0; 692 if (field_type == "Ch") { 693 return (flags & (1 << 17)) 694 ? CPVT_GenerateAP::GenerateComboBoxAP(pDoc, pAnnotDict) 695 : CPVT_GenerateAP::GenerateListBoxAP(pDoc, pAnnotDict); 696 } 697 698 if (field_type == "Btn") { 699 if (!(flags & (1 << 16))) { 700 if (!pAnnotDict->KeyExist("AS")) { 701 if (CPDF_Dictionary* pParentDict = pAnnotDict->GetDictFor("Parent")) { 702 if (pParentDict->KeyExist("AS")) { 703 pAnnotDict->SetNewFor<CPDF_String>( 704 "AS", pParentDict->GetStringFor("AS"), false); 705 } 706 } 707 } 708 } 709 } 710 711 return false; 712} 713 714// Static. 715bool CPVT_GenerateAP::GenerateComboBoxAP(CPDF_Document* pDoc, 716 CPDF_Dictionary* pAnnotDict) { 717 return GenerateWidgetAP(pDoc, pAnnotDict, 1); 718} 719 720// Static. 721bool CPVT_GenerateAP::GenerateListBoxAP(CPDF_Document* pDoc, 722 CPDF_Dictionary* pAnnotDict) { 723 return GenerateWidgetAP(pDoc, pAnnotDict, 2); 724} 725 726// Static. 727bool CPVT_GenerateAP::GenerateTextFieldAP(CPDF_Document* pDoc, 728 CPDF_Dictionary* pAnnotDict) { 729 return GenerateWidgetAP(pDoc, pAnnotDict, 0); 730} 731 732bool CPVT_GenerateAP::GenerateCircleAP(CPDF_Document* pDoc, 733 CPDF_Dictionary* pAnnotDict) { 734 CFX_ByteTextBuf sAppStream; 735 CFX_ByteString sExtGSDictName = "GS"; 736 sAppStream << "/" << sExtGSDictName << " gs "; 737 738 CPDF_Array* pInteriorColor = pAnnotDict->GetArrayFor("IC"); 739 sAppStream << GetColorStringWithDefault(pInteriorColor, 740 CPVT_Color(CPVT_Color::kTransparent), 741 PaintOperation::FILL); 742 743 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"), 744 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), 745 PaintOperation::STROKE); 746 747 FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict); 748 bool bIsStrokeRect = fBorderWidth > 0; 749 750 if (bIsStrokeRect) { 751 sAppStream << fBorderWidth << " w "; 752 sAppStream << GetDashPatternString(*pAnnotDict); 753 } 754 755 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect"); 756 rect.Normalize(); 757 758 if (bIsStrokeRect) { 759 // Deflating rect because stroking a path entails painting all points whose 760 // perpendicular distance from the path in user space is less than or equal 761 // to half the line width. 762 rect.Deflate(fBorderWidth / 2, fBorderWidth / 2); 763 } 764 765 const FX_FLOAT fMiddleX = (rect.left + rect.right) / 2; 766 const FX_FLOAT fMiddleY = (rect.top + rect.bottom) / 2; 767 768 // |fL| is precalculated approximate value of 4 * tan((3.14 / 2) / 4) / 3, 769 // where |fL| * radius is a good approximation of control points for 770 // arc with 90 degrees. 771 const FX_FLOAT fL = 0.5523f; 772 const FX_FLOAT fDeltaX = fL * rect.Width() / 2.0; 773 const FX_FLOAT fDeltaY = fL * rect.Height() / 2.0; 774 775 // Starting point 776 sAppStream << fMiddleX << " " << rect.top << " m\n"; 777 // First Bezier Curve 778 sAppStream << fMiddleX + fDeltaX << " " << rect.top << " " << rect.right 779 << " " << fMiddleY + fDeltaY << " " << rect.right << " " 780 << fMiddleY << " c\n"; 781 // Second Bezier Curve 782 sAppStream << rect.right << " " << fMiddleY - fDeltaY << " " 783 << fMiddleX + fDeltaX << " " << rect.bottom << " " << fMiddleX 784 << " " << rect.bottom << " c\n"; 785 // Third Bezier Curve 786 sAppStream << fMiddleX - fDeltaX << " " << rect.bottom << " " << rect.left 787 << " " << fMiddleY - fDeltaY << " " << rect.left << " " << fMiddleY 788 << " c\n"; 789 // Fourth Bezier Curve 790 sAppStream << rect.left << " " << fMiddleY + fDeltaY << " " 791 << fMiddleX - fDeltaX << " " << rect.top << " " << fMiddleX << " " 792 << rect.top << " c\n"; 793 794 bool bIsFillRect = pInteriorColor && !pInteriorColor->IsEmpty(); 795 sAppStream << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n"; 796 797 auto pExtGStateDict = 798 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); 799 auto pResourceDict = 800 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); 801 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict), 802 false /*IsTextMarkupAnnotation*/); 803 return true; 804} 805 806bool CPVT_GenerateAP::GenerateHighlightAP(CPDF_Document* pDoc, 807 CPDF_Dictionary* pAnnotDict) { 808 CFX_ByteTextBuf sAppStream; 809 CFX_ByteString sExtGSDictName = "GS"; 810 sAppStream << "/" << sExtGSDictName << " gs "; 811 812 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"), 813 CPVT_Color(CPVT_Color::kRGB, 1, 1, 0), 814 PaintOperation::FILL); 815 816 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict); 817 rect.Normalize(); 818 819 sAppStream << rect.left << " " << rect.top << " m " << rect.right << " " 820 << rect.top << " l " << rect.right << " " << rect.bottom << " l " 821 << rect.left << " " << rect.bottom << " l " 822 << "h f\n"; 823 824 auto pExtGStateDict = 825 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Multiply"); 826 auto pResourceDict = 827 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); 828 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict), 829 true /*IsTextMarkupAnnotation*/); 830 831 return true; 832} 833 834bool CPVT_GenerateAP::GenerateInkAP(CPDF_Document* pDoc, 835 CPDF_Dictionary* pAnnotDict) { 836 FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict); 837 bool bIsStroke = fBorderWidth > 0; 838 839 if (!bIsStroke) 840 return false; 841 842 CPDF_Array* pInkList = pAnnotDict->GetArrayFor("InkList"); 843 if (!pInkList || pInkList->IsEmpty()) 844 return false; 845 846 CFX_ByteTextBuf sAppStream; 847 CFX_ByteString sExtGSDictName = "GS"; 848 sAppStream << "/" << sExtGSDictName << " gs "; 849 850 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"), 851 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), 852 PaintOperation::STROKE); 853 854 sAppStream << fBorderWidth << " w "; 855 sAppStream << GetDashPatternString(*pAnnotDict); 856 857 // Set inflated rect as a new rect because paths near the border with large 858 // width should not be clipped to the original rect. 859 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect"); 860 rect.Inflate(fBorderWidth / 2, fBorderWidth / 2); 861 pAnnotDict->SetRectFor("Rect", rect); 862 863 for (size_t i = 0; i < pInkList->GetCount(); i++) { 864 CPDF_Array* pInkCoordList = pInkList->GetArrayAt(i); 865 if (!pInkCoordList || pInkCoordList->GetCount() < 2) 866 continue; 867 868 sAppStream << pInkCoordList->GetNumberAt(0) << " " 869 << pInkCoordList->GetNumberAt(1) << " m "; 870 871 for (size_t j = 0; j < pInkCoordList->GetCount() - 1; j += 2) { 872 sAppStream << pInkCoordList->GetNumberAt(j) << " " 873 << pInkCoordList->GetNumberAt(j + 1) << " l "; 874 } 875 876 sAppStream << "S\n"; 877 } 878 879 auto pExtGStateDict = 880 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); 881 auto pResourceDict = 882 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); 883 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict), 884 false /*IsTextMarkupAnnotation*/); 885 return true; 886} 887 888bool CPVT_GenerateAP::GenerateTextAP(CPDF_Document* pDoc, 889 CPDF_Dictionary* pAnnotDict) { 890 CFX_ByteTextBuf sAppStream; 891 CFX_ByteString sExtGSDictName = "GS"; 892 sAppStream << "/" << sExtGSDictName << " gs "; 893 894 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect"); 895 const FX_FLOAT fNoteLength = 20; 896 CFX_FloatRect noteRect(rect.left, rect.bottom, rect.left + fNoteLength, 897 rect.bottom + fNoteLength); 898 pAnnotDict->SetRectFor("Rect", noteRect); 899 900 sAppStream << GenerateTextSymbolAP(noteRect); 901 902 auto pExtGStateDict = 903 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); 904 auto pResourceDict = 905 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); 906 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict), 907 false /*IsTextMarkupAnnotation*/); 908 return true; 909} 910 911bool CPVT_GenerateAP::GenerateUnderlineAP(CPDF_Document* pDoc, 912 CPDF_Dictionary* pAnnotDict) { 913 CFX_ByteTextBuf sAppStream; 914 CFX_ByteString sExtGSDictName = "GS"; 915 sAppStream << "/" << sExtGSDictName << " gs "; 916 917 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"), 918 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), 919 PaintOperation::STROKE); 920 921 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict); 922 rect.Normalize(); 923 924 FX_FLOAT fLineWidth = 1.0; 925 sAppStream << fLineWidth << " w " << rect.left << " " 926 << rect.bottom + fLineWidth << " m " << rect.right << " " 927 << rect.bottom + fLineWidth << " l S\n"; 928 929 auto pExtGStateDict = 930 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); 931 auto pResourceDict = 932 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); 933 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict), 934 true /*IsTextMarkupAnnotation*/); 935 return true; 936} 937 938bool CPVT_GenerateAP::GeneratePopupAP(CPDF_Document* pDoc, 939 CPDF_Dictionary* pAnnotDict) { 940 CFX_ByteTextBuf sAppStream; 941 CFX_ByteString sExtGSDictName = "GS"; 942 sAppStream << "/" << sExtGSDictName << " gs\n"; 943 944 sAppStream << GenerateColorAP(CPVT_Color(CPVT_Color::kRGB, 1, 1, 0), 945 PaintOperation::FILL); 946 sAppStream << GenerateColorAP(CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), 947 PaintOperation::STROKE); 948 949 const FX_FLOAT fBorderWidth = 1; 950 sAppStream << fBorderWidth << " w\n"; 951 952 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect"); 953 rect.Normalize(); 954 rect.Deflate(fBorderWidth / 2, fBorderWidth / 2); 955 956 sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " " 957 << rect.Height() << " re b\n"; 958 959 CFX_ByteString sFontName = "FONT"; 960 auto pResourceFontDict = GenerateResourceFontDict(pDoc, sFontName); 961 CPDF_Font* pDefFont = pDoc->LoadFont(pResourceFontDict.get()); 962 if (!pDefFont) 963 return false; 964 965 auto pExtGStateDict = 966 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); 967 auto pResourceDict = GenerateResourceDict(pDoc, std::move(pResourceFontDict), 968 std::move(pExtGStateDict)); 969 970 sAppStream << GetPopupContentsString(pDoc, *pAnnotDict, pDefFont, sFontName); 971 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict), 972 false /*IsTextMarkupAnnotation*/); 973 return true; 974} 975 976bool CPVT_GenerateAP::GenerateSquareAP(CPDF_Document* pDoc, 977 CPDF_Dictionary* pAnnotDict) { 978 CFX_ByteTextBuf sAppStream; 979 CFX_ByteString sExtGSDictName = "GS"; 980 sAppStream << "/" << sExtGSDictName << " gs "; 981 982 CPDF_Array* pInteriorColor = pAnnotDict->GetArrayFor("IC"); 983 sAppStream << GetColorStringWithDefault(pInteriorColor, 984 CPVT_Color(CPVT_Color::kTransparent), 985 PaintOperation::FILL); 986 987 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"), 988 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), 989 PaintOperation::STROKE); 990 991 FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict); 992 bool bIsStrokeRect = fBorderWidth > 0; 993 994 if (bIsStrokeRect) { 995 sAppStream << fBorderWidth << " w "; 996 sAppStream << GetDashPatternString(*pAnnotDict); 997 } 998 999 CFX_FloatRect rect = pAnnotDict->GetRectFor("Rect"); 1000 rect.Normalize(); 1001 1002 if (bIsStrokeRect) { 1003 // Deflating rect because stroking a path entails painting all points whose 1004 // perpendicular distance from the path in user space is less than or equal 1005 // to half the line width. 1006 rect.Deflate(fBorderWidth / 2, fBorderWidth / 2); 1007 } 1008 1009 bool bIsFillRect = pInteriorColor && (pInteriorColor->GetCount() > 0); 1010 1011 sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " " 1012 << rect.Height() << " re " 1013 << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n"; 1014 1015 auto pExtGStateDict = 1016 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); 1017 auto pResourceDict = 1018 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); 1019 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict), 1020 false /*IsTextMarkupAnnotation*/); 1021 return true; 1022} 1023 1024bool CPVT_GenerateAP::GenerateSquigglyAP(CPDF_Document* pDoc, 1025 CPDF_Dictionary* pAnnotDict) { 1026 CFX_ByteTextBuf sAppStream; 1027 CFX_ByteString sExtGSDictName = "GS"; 1028 sAppStream << "/" << sExtGSDictName << " gs "; 1029 1030 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"), 1031 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), 1032 PaintOperation::STROKE); 1033 1034 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict); 1035 rect.Normalize(); 1036 1037 FX_FLOAT fLineWidth = 1.0; 1038 sAppStream << fLineWidth << " w "; 1039 1040 const FX_FLOAT fDelta = 2.0; 1041 const FX_FLOAT fTop = rect.bottom + fDelta; 1042 const FX_FLOAT fBottom = rect.bottom; 1043 1044 sAppStream << rect.left << " " << fTop << " m "; 1045 1046 FX_FLOAT fX = rect.left + fDelta; 1047 bool isUpwards = false; 1048 1049 while (fX < rect.right) { 1050 sAppStream << fX << " " << (isUpwards ? fTop : fBottom) << " l "; 1051 1052 fX += fDelta; 1053 isUpwards = !isUpwards; 1054 } 1055 1056 FX_FLOAT fRemainder = rect.right - (fX - fDelta); 1057 if (isUpwards) 1058 sAppStream << rect.right << " " << fBottom + fRemainder << " l "; 1059 else 1060 sAppStream << rect.right << " " << fTop - fRemainder << " l "; 1061 1062 sAppStream << "S\n"; 1063 1064 auto pExtGStateDict = 1065 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); 1066 auto pResourceDict = 1067 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); 1068 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict), 1069 true /*IsTextMarkupAnnotation*/); 1070 return true; 1071} 1072 1073bool CPVT_GenerateAP::GenerateStrikeOutAP(CPDF_Document* pDoc, 1074 CPDF_Dictionary* pAnnotDict) { 1075 CFX_ByteTextBuf sAppStream; 1076 CFX_ByteString sExtGSDictName = "GS"; 1077 sAppStream << "/" << sExtGSDictName << " gs "; 1078 1079 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayFor("C"), 1080 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), 1081 PaintOperation::STROKE); 1082 1083 CFX_FloatRect rect = CPDF_Annot::RectFromQuadPoints(pAnnotDict); 1084 rect.Normalize(); 1085 1086 FX_FLOAT fLineWidth = 1.0; 1087 FX_FLOAT fY = (rect.top + rect.bottom) / 2; 1088 sAppStream << fLineWidth << " w " << rect.left << " " << fY << " m " 1089 << rect.right << " " << fY << " l S\n"; 1090 1091 auto pExtGStateDict = 1092 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); 1093 auto pResourceDict = 1094 GenerateResourceDict(pDoc, std::move(pExtGStateDict), nullptr); 1095 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, std::move(pResourceDict), 1096 true /*IsTextMarkupAnnotation*/); 1097 return true; 1098} 1099 1100// Static. 1101CFX_ByteString CPVT_GenerateAP::GenerateEditAP( 1102 IPVT_FontMap* pFontMap, 1103 CPDF_VariableText::Iterator* pIterator, 1104 const CFX_PointF& ptOffset, 1105 bool bContinuous, 1106 uint16_t SubWord) { 1107 CFX_ByteTextBuf sEditStream; 1108 CFX_ByteTextBuf sLineStream; 1109 CFX_ByteTextBuf sWords; 1110 CFX_PointF ptOld; 1111 CFX_PointF ptNew; 1112 int32_t nCurFontIndex = -1; 1113 CPVT_WordPlace oldplace; 1114 1115 pIterator->SetAt(0); 1116 while (pIterator->NextWord()) { 1117 CPVT_WordPlace place = pIterator->GetAt(); 1118 if (bContinuous) { 1119 if (place.LineCmp(oldplace) != 0) { 1120 if (sWords.GetSize() > 0) { 1121 sLineStream << GetWordRenderString(sWords.MakeString()); 1122 sEditStream << sLineStream; 1123 sLineStream.Clear(); 1124 sWords.Clear(); 1125 } 1126 CPVT_Word word; 1127 if (pIterator->GetWord(word)) { 1128 ptNew = CFX_PointF(word.ptWord.x + ptOffset.x, 1129 word.ptWord.y + ptOffset.y); 1130 } else { 1131 CPVT_Line line; 1132 pIterator->GetLine(line); 1133 ptNew = CFX_PointF(line.ptLine.x + ptOffset.x, 1134 line.ptLine.y + ptOffset.y); 1135 } 1136 if (ptNew != ptOld) { 1137 sLineStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y 1138 << " Td\n"; 1139 ptOld = ptNew; 1140 } 1141 } 1142 CPVT_Word word; 1143 if (pIterator->GetWord(word)) { 1144 if (word.nFontIndex != nCurFontIndex) { 1145 if (sWords.GetSize() > 0) { 1146 sLineStream << GetWordRenderString(sWords.MakeString()); 1147 sWords.Clear(); 1148 } 1149 sLineStream << GetFontSetString(pFontMap, word.nFontIndex, 1150 word.fFontSize); 1151 nCurFontIndex = word.nFontIndex; 1152 } 1153 sWords << GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord); 1154 } 1155 oldplace = place; 1156 } else { 1157 CPVT_Word word; 1158 if (pIterator->GetWord(word)) { 1159 ptNew = 1160 CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y); 1161 if (ptNew != ptOld) { 1162 sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y 1163 << " Td\n"; 1164 ptOld = ptNew; 1165 } 1166 if (word.nFontIndex != nCurFontIndex) { 1167 sEditStream << GetFontSetString(pFontMap, word.nFontIndex, 1168 word.fFontSize); 1169 nCurFontIndex = word.nFontIndex; 1170 } 1171 sEditStream << GetWordRenderString( 1172 GetPDFWordString(pFontMap, nCurFontIndex, word.Word, SubWord)); 1173 } 1174 } 1175 } 1176 if (sWords.GetSize() > 0) { 1177 sLineStream << GetWordRenderString(sWords.MakeString()); 1178 sEditStream << sLineStream; 1179 sWords.Clear(); 1180 } 1181 return sEditStream.MakeString(); 1182} 1183 1184// Static. 1185CFX_ByteString CPVT_GenerateAP::GenerateBorderAP( 1186 const CFX_FloatRect& rect, 1187 FX_FLOAT fWidth, 1188 const CPVT_Color& color, 1189 const CPVT_Color& crLeftTop, 1190 const CPVT_Color& crRightBottom, 1191 BorderStyle nStyle, 1192 const CPVT_Dash& dash) { 1193 CFX_ByteTextBuf sAppStream; 1194 CFX_ByteString sColor; 1195 FX_FLOAT fLeft = rect.left; 1196 FX_FLOAT fRight = rect.right; 1197 FX_FLOAT fTop = rect.top; 1198 FX_FLOAT fBottom = rect.bottom; 1199 if (fWidth > 0.0f) { 1200 FX_FLOAT fHalfWidth = fWidth / 2.0f; 1201 switch (nStyle) { 1202 default: 1203 case BorderStyle::SOLID: 1204 sColor = GenerateColorAP(color, PaintOperation::FILL); 1205 if (sColor.GetLength() > 0) { 1206 sAppStream << sColor; 1207 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " 1208 << fTop - fBottom << " re\n"; 1209 sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " " 1210 << fRight - fLeft - fWidth * 2 << " " 1211 << fTop - fBottom - fWidth * 2 << " re\n"; 1212 sAppStream << "f*\n"; 1213 } 1214 break; 1215 case BorderStyle::DASH: 1216 sColor = GenerateColorAP(color, PaintOperation::STROKE); 1217 if (sColor.GetLength() > 0) { 1218 sAppStream << sColor; 1219 sAppStream << fWidth << " w" 1220 << " [" << dash.nDash << " " << dash.nGap << "] " 1221 << dash.nPhase << " d\n"; 1222 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 1223 << " m\n"; 1224 sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2 1225 << " l\n"; 1226 sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2 1227 << " l\n"; 1228 sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2 1229 << " l\n"; 1230 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 1231 << " l S\n"; 1232 } 1233 break; 1234 case BorderStyle::BEVELED: 1235 case BorderStyle::INSET: 1236 sColor = GenerateColorAP(crLeftTop, PaintOperation::FILL); 1237 if (sColor.GetLength() > 0) { 1238 sAppStream << sColor; 1239 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth 1240 << " m\n"; 1241 sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth 1242 << " l\n"; 1243 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth 1244 << " l\n"; 1245 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 1246 << " l\n"; 1247 sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 1248 << " l\n"; 1249 sAppStream << fLeft + fHalfWidth * 2 << " " 1250 << fBottom + fHalfWidth * 2 << " l f\n"; 1251 } 1252 sColor = GenerateColorAP(crRightBottom, PaintOperation::FILL); 1253 if (sColor.GetLength() > 0) { 1254 sAppStream << sColor; 1255 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth 1256 << " m\n"; 1257 sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth 1258 << " l\n"; 1259 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth 1260 << " l\n"; 1261 sAppStream << fLeft + fHalfWidth * 2 << " " 1262 << fBottom + fHalfWidth * 2 << " l\n"; 1263 sAppStream << fRight - fHalfWidth * 2 << " " 1264 << fBottom + fHalfWidth * 2 << " l\n"; 1265 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2 1266 << " l f\n"; 1267 } 1268 sColor = GenerateColorAP(color, PaintOperation::FILL); 1269 if (sColor.GetLength() > 0) { 1270 sAppStream << sColor; 1271 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " " 1272 << fTop - fBottom << " re\n"; 1273 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " " 1274 << fRight - fLeft - fHalfWidth * 2 << " " 1275 << fTop - fBottom - fHalfWidth * 2 << " re f*\n"; 1276 } 1277 break; 1278 case BorderStyle::UNDERLINE: 1279 sColor = GenerateColorAP(color, PaintOperation::STROKE); 1280 if (sColor.GetLength() > 0) { 1281 sAppStream << sColor; 1282 sAppStream << fWidth << " w\n"; 1283 sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n"; 1284 sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n"; 1285 } 1286 break; 1287 } 1288 } 1289 return sAppStream.MakeString(); 1290} 1291 1292// Static. 1293CFX_ByteString CPVT_GenerateAP::GenerateColorAP(const CPVT_Color& color, 1294 PaintOperation nOperation) { 1295 CFX_ByteTextBuf sColorStream; 1296 switch (color.nColorType) { 1297 case CPVT_Color::kRGB: 1298 sColorStream << color.fColor1 << " " << color.fColor2 << " " 1299 << color.fColor3 << " " 1300 << (nOperation == PaintOperation::STROKE ? "RG" : "rg") 1301 << "\n"; 1302 break; 1303 case CPVT_Color::kGray: 1304 sColorStream << color.fColor1 << " " 1305 << (nOperation == PaintOperation::STROKE ? "G" : "g") 1306 << "\n"; 1307 break; 1308 case CPVT_Color::kCMYK: 1309 sColorStream << color.fColor1 << " " << color.fColor2 << " " 1310 << color.fColor3 << " " << color.fColor4 << " " 1311 << (nOperation == PaintOperation::STROKE ? "K" : "k") 1312 << "\n"; 1313 break; 1314 case CPVT_Color::kTransparent: 1315 break; 1316 } 1317 return sColorStream.MakeString(); 1318} 1319 1320// Static. 1321CFX_ByteString CPVT_GenerateAP::GetPDFWordString(IPVT_FontMap* pFontMap, 1322 int32_t nFontIndex, 1323 uint16_t Word, 1324 uint16_t SubWord) { 1325 CFX_ByteString sWord; 1326 if (SubWord > 0) { 1327 sWord.Format("%c", SubWord); 1328 return sWord; 1329 } 1330 1331 if (!pFontMap) 1332 return sWord; 1333 1334 if (CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex)) { 1335 if (pPDFFont->GetBaseFont().Compare("Symbol") == 0 || 1336 pPDFFont->GetBaseFont().Compare("ZapfDingbats") == 0) { 1337 sWord.Format("%c", Word); 1338 } else { 1339 uint32_t dwCharCode = pPDFFont->CharCodeFromUnicode(Word); 1340 if (dwCharCode != CPDF_Font::kInvalidCharCode) 1341 pPDFFont->AppendChar(sWord, dwCharCode); 1342 } 1343 } 1344 return sWord; 1345} 1346 1347// Static. 1348CFX_ByteString CPVT_GenerateAP::GetWordRenderString( 1349 const CFX_ByteString& strWords) { 1350 if (strWords.GetLength() > 0) 1351 return PDF_EncodeString(strWords) + " Tj\n"; 1352 return ""; 1353} 1354 1355// Static. 1356CFX_ByteString CPVT_GenerateAP::GetFontSetString(IPVT_FontMap* pFontMap, 1357 int32_t nFontIndex, 1358 FX_FLOAT fFontSize) { 1359 CFX_ByteTextBuf sRet; 1360 if (pFontMap) { 1361 CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex); 1362 if (sFontAlias.GetLength() > 0 && fFontSize > 0) 1363 sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n"; 1364 } 1365 return sRet.MakeString(); 1366} 1367