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