Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 PDFium Authors. All rights reserved. | 1 // Copyright 2016 PDFium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| 6 | 6 |
| 7 #include "core/fpdfdoc/cpvt_generateap.h" | 7 #include "core/fpdfdoc/cpvt_generateap.h" |
| 8 | 8 |
| 9 #include "core/fpdfapi/fpdf_font/include/cpdf_font.h" | 9 #include "core/fpdfapi/fpdf_font/include/cpdf_font.h" |
| 10 #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" | 10 #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" |
| (...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 445 pStreamResFontList->SetAtReference(sFontName, pDoc, pFontDict); | 445 pStreamResFontList->SetAtReference(sFontName, pDoc, pFontDict); |
| 446 } else { | 446 } else { |
| 447 pStreamDict->SetAt("Resources", pFormDict->GetDictBy("DR")->Clone()); | 447 pStreamDict->SetAt("Resources", pFormDict->GetDictBy("DR")->Clone()); |
| 448 pStreamResList = pStreamDict->GetDictBy("Resources"); | 448 pStreamResList = pStreamDict->GetDictBy("Resources"); |
| 449 } | 449 } |
| 450 } | 450 } |
| 451 } | 451 } |
| 452 return true; | 452 return true; |
| 453 } | 453 } |
| 454 | 454 |
| 455 CFX_ByteString GetColorStringWithDefault(CPDF_Dictionary* pAnnotDict, | 455 CFX_ByteString GetColorStringWithDefault(CPDF_Array* pColor, |
| 456 const CPVT_Color& crDefaultColor, | 456 const CPVT_Color& crDefaultColor, |
| 457 PaintOperation nOperation) { | 457 PaintOperation nOperation) { |
| 458 if (CPDF_Array* pColor = pAnnotDict->GetArrayBy("C")) { | 458 if (pColor) { |
| 459 CPVT_Color color = CPVT_Color::ParseColor(*pColor); | 459 CPVT_Color color = CPVT_Color::ParseColor(*pColor); |
| 460 return CPVT_GenerateAP::GenerateColorAP(color, nOperation); | 460 return CPVT_GenerateAP::GenerateColorAP(color, nOperation); |
| 461 } | 461 } |
| 462 | 462 |
| 463 return CPVT_GenerateAP::GenerateColorAP(crDefaultColor, nOperation); | 463 return CPVT_GenerateAP::GenerateColorAP(crDefaultColor, nOperation); |
| 464 } | 464 } |
| 465 | 465 |
| 466 FX_FLOAT GetBorderWidth(const CPDF_Dictionary& pAnnotDict) { | |
| 467 if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictBy("BS")) { | |
| 468 if (pBorderStyleDict->KeyExist("W")) | |
| 469 return pBorderStyleDict->GetNumberBy("W"); | |
| 470 } | |
| 471 | |
| 472 if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayBy("Border")) { | |
| 473 if (pBorderArray->GetCount() > 2) | |
| 474 return pBorderArray->GetNumberAt(2); | |
| 475 } | |
| 476 | |
| 477 return 1; | |
| 478 } | |
| 479 | |
| 480 CPDF_Array* GetDashArray(const CPDF_Dictionary& pAnnotDict) { | |
| 481 if (CPDF_Dictionary* pBorderStyleDict = pAnnotDict.GetDictBy("BS")) { | |
| 482 if (pBorderStyleDict->GetStringBy("S") == "D") | |
| 483 return pBorderStyleDict->GetArrayBy("D"); | |
| 484 } | |
| 485 | |
| 486 if (CPDF_Array* pBorderArray = pAnnotDict.GetArrayBy("Border")) { | |
| 487 if (pBorderArray->GetCount() == 4) | |
| 488 return pBorderArray->GetArrayAt(3); | |
| 489 } | |
| 490 | |
| 491 return nullptr; | |
| 492 } | |
| 493 | |
| 494 CFX_ByteString GetDashPatternString(const CPDF_Dictionary& pAnnotDict) { | |
| 495 CPDF_Array* pDashArray = GetDashArray(pAnnotDict); | |
| 496 if (!pDashArray) | |
| 497 return CFX_ByteString(); | |
| 498 | |
| 499 size_t pDashArrayCount = pDashArray->GetCount(); | |
| 500 if (pDashArrayCount == 0 || pDashArrayCount > 10) | |
|
Lei Zhang
2016/08/08 23:10:41
BTW, do you want to make a sample PDF where the ar
jaepark
2016/08/09 00:11:03
I've changed it to truncate at 10.
| |
| 501 return CFX_ByteString(); | |
| 502 | |
| 503 CFX_ByteTextBuf sDashStream; | |
| 504 sDashStream << "["; | |
| 505 for (size_t i = 0; i < pDashArrayCount; ++i) | |
| 506 sDashStream << pDashArray->GetNumberAt(i) << " "; | |
| 507 sDashStream << "] 0 d\n"; | |
| 508 | |
| 509 return sDashStream.MakeString(); | |
| 510 } | |
| 511 | |
| 466 CPDF_Dictionary* GenerateExtGStateDict(const CPDF_Dictionary& pAnnotDict, | 512 CPDF_Dictionary* GenerateExtGStateDict(const CPDF_Dictionary& pAnnotDict, |
| 467 const CFX_ByteString& sExtGSDictName, | 513 const CFX_ByteString& sExtGSDictName, |
| 468 const CFX_ByteString& sBlendMode) { | 514 const CFX_ByteString& sBlendMode) { |
| 469 CPDF_Dictionary* pGSDict = new CPDF_Dictionary; | 515 CPDF_Dictionary* pGSDict = new CPDF_Dictionary; |
| 470 pGSDict->SetAtString("Type", "ExtGState"); | 516 pGSDict->SetAtString("Type", "ExtGState"); |
| 471 | 517 |
| 472 FX_FLOAT fOpacity = | 518 FX_FLOAT fOpacity = |
| 473 pAnnotDict.KeyExist("CA") ? pAnnotDict.GetNumberBy("CA") : 1; | 519 pAnnotDict.KeyExist("CA") ? pAnnotDict.GetNumberBy("CA") : 1; |
| 474 pGSDict->SetAtNumber("CA", fOpacity); | 520 pGSDict->SetAtNumber("CA", fOpacity); |
| 475 pGSDict->SetAtNumber("ca", fOpacity); | 521 pGSDict->SetAtNumber("ca", fOpacity); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 504 | 550 |
| 505 CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); | 551 CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); |
| 506 pStreamDict->SetAtRect("BBox", rect); | 552 pStreamDict->SetAtRect("BBox", rect); |
| 507 | 553 |
| 508 CPDF_Dictionary* pResourceDict = new CPDF_Dictionary; | 554 CPDF_Dictionary* pResourceDict = new CPDF_Dictionary; |
| 509 pResourceDict->SetAt("ExtGState", pExtGStateDict); | 555 pResourceDict->SetAt("ExtGState", pExtGStateDict); |
| 510 | 556 |
| 511 pStreamDict->SetAt("Resources", pResourceDict); | 557 pStreamDict->SetAt("Resources", pResourceDict); |
| 512 } | 558 } |
| 513 | 559 |
| 560 CFX_ByteString GetPaintOperatorString(bool bIsStrokeRect, bool bIsFillRect) { | |
| 561 if (bIsStrokeRect) | |
| 562 return bIsFillRect ? "b" : "s"; | |
| 563 return bIsFillRect ? "f" : "n"; | |
| 564 } | |
| 565 | |
| 514 } // namespace | 566 } // namespace |
| 515 | 567 |
| 516 bool FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { | 568 bool FPDF_GenerateAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) { |
| 517 if (!pAnnotDict || pAnnotDict->GetStringBy("Subtype") != "Widget") | 569 if (!pAnnotDict || pAnnotDict->GetStringBy("Subtype") != "Widget") |
| 518 return false; | 570 return false; |
| 519 | 571 |
| 520 CFX_ByteString field_type = FPDF_GetFieldAttr(pAnnotDict, "FT")->GetString(); | 572 CFX_ByteString field_type = FPDF_GetFieldAttr(pAnnotDict, "FT")->GetString(); |
| 521 uint32_t flags = FPDF_GetFieldAttr(pAnnotDict, "Ff") | 573 uint32_t flags = FPDF_GetFieldAttr(pAnnotDict, "Ff") |
| 522 ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger() | 574 ? FPDF_GetFieldAttr(pAnnotDict, "Ff")->GetInteger() |
| 523 : 0; | 575 : 0; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 565 CPDF_Dictionary* pAnnotDict) { | 617 CPDF_Dictionary* pAnnotDict) { |
| 566 // If AP dictionary exists, we use the appearance defined in the | 618 // If AP dictionary exists, we use the appearance defined in the |
| 567 // existing AP dictionary. | 619 // existing AP dictionary. |
| 568 if (pAnnotDict->KeyExist("AP")) | 620 if (pAnnotDict->KeyExist("AP")) |
| 569 return false; | 621 return false; |
| 570 | 622 |
| 571 CFX_ByteTextBuf sAppStream; | 623 CFX_ByteTextBuf sAppStream; |
| 572 CFX_ByteString sExtGSDictName = "GS"; | 624 CFX_ByteString sExtGSDictName = "GS"; |
| 573 sAppStream << "/" << sExtGSDictName << " gs "; | 625 sAppStream << "/" << sExtGSDictName << " gs "; |
| 574 | 626 |
| 575 sAppStream << GetColorStringWithDefault( | 627 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayBy("C"), |
| 576 pAnnotDict, CPVT_Color(CPVT_Color::kRGB, 1, 1, 0), PaintOperation::FILL); | 628 CPVT_Color(CPVT_Color::kRGB, 1, 1, 0), |
| 629 PaintOperation::FILL); | |
| 577 | 630 |
| 578 CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); | 631 CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); |
| 579 rect.Normalize(); | 632 rect.Normalize(); |
| 580 | 633 |
| 581 sAppStream << rect.left << " " << rect.top << " m " << rect.right << " " | 634 sAppStream << rect.left << " " << rect.top << " m " << rect.right << " " |
| 582 << rect.top << " l " << rect.right << " " << rect.bottom << " l " | 635 << rect.top << " l " << rect.right << " " << rect.bottom << " l " |
| 583 << rect.left << " " << rect.bottom << " l " | 636 << rect.left << " " << rect.bottom << " l " |
| 584 << "h f\n"; | 637 << "h f\n"; |
| 585 | 638 |
| 586 CPDF_Dictionary* pExtGStateDict = | 639 CPDF_Dictionary* pExtGStateDict = |
| 587 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Multiply"); | 640 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Multiply"); |
| 588 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict); | 641 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict); |
| 589 | 642 |
| 590 return true; | 643 return true; |
| 591 } | 644 } |
| 592 | 645 |
| 593 bool CPVT_GenerateAP::GenerateUnderlineAP(CPDF_Document* pDoc, | 646 bool CPVT_GenerateAP::GenerateUnderlineAP(CPDF_Document* pDoc, |
| 594 CPDF_Dictionary* pAnnotDict) { | 647 CPDF_Dictionary* pAnnotDict) { |
| 595 // If AP dictionary exists, we use the appearance defined in the | 648 // If AP dictionary exists, we use the appearance defined in the |
| 596 // existing AP dictionary. | 649 // existing AP dictionary. |
| 597 if (pAnnotDict->KeyExist("AP")) | 650 if (pAnnotDict->KeyExist("AP")) |
| 598 return false; | 651 return false; |
| 599 | 652 |
| 600 CFX_ByteTextBuf sAppStream; | 653 CFX_ByteTextBuf sAppStream; |
| 601 CFX_ByteString sExtGSDictName = "GS"; | 654 CFX_ByteString sExtGSDictName = "GS"; |
| 602 sAppStream << "/" << sExtGSDictName << " gs "; | 655 sAppStream << "/" << sExtGSDictName << " gs "; |
| 603 | 656 |
| 604 sAppStream << GetColorStringWithDefault(pAnnotDict, | 657 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayBy("C"), |
| 605 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), | 658 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), |
| 606 PaintOperation::STROKE); | 659 PaintOperation::STROKE); |
| 607 | 660 |
| 608 CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); | 661 CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); |
| 609 rect.Normalize(); | 662 rect.Normalize(); |
| 610 | 663 |
| 611 FX_FLOAT fLineWidth = 1.0; | 664 FX_FLOAT fLineWidth = 1.0; |
| 612 sAppStream << fLineWidth << " w " << rect.left << " " | 665 sAppStream << fLineWidth << " w " << rect.left << " " |
| 613 << rect.bottom + fLineWidth << " m " << rect.right << " " | 666 << rect.bottom + fLineWidth << " m " << rect.right << " " |
| 614 << rect.bottom + fLineWidth << " l S\n"; | 667 << rect.bottom + fLineWidth << " l S\n"; |
| 615 | 668 |
| 616 CPDF_Dictionary* pExtGStateDict = | 669 CPDF_Dictionary* pExtGStateDict = |
| 617 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); | 670 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); |
| 618 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict); | 671 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict); |
| 619 return true; | 672 return true; |
| 620 } | 673 } |
| 621 | 674 |
| 675 bool CPVT_GenerateAP::GenerateSquareAP(CPDF_Document* pDoc, | |
| 676 CPDF_Dictionary* pAnnotDict) { | |
| 677 // If AP dictionary exists, we use the appearance defined in the | |
| 678 // existing AP dictionary. | |
| 679 if (pAnnotDict->KeyExist("AP")) | |
| 680 return false; | |
| 681 | |
| 682 CFX_ByteTextBuf sAppStream; | |
| 683 CFX_ByteString sExtGSDictName = "GS"; | |
| 684 sAppStream << "/" << sExtGSDictName << " gs "; | |
| 685 | |
| 686 CPDF_Array* pInteriorColor = pAnnotDict->GetArrayBy("IC"); | |
| 687 sAppStream << GetColorStringWithDefault(pInteriorColor, | |
| 688 CPVT_Color(CPVT_Color::kTransparent), | |
| 689 PaintOperation::FILL); | |
| 690 | |
| 691 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayBy("C"), | |
| 692 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), | |
| 693 PaintOperation::STROKE); | |
| 694 | |
| 695 FX_FLOAT fBorderWidth = GetBorderWidth(*pAnnotDict); | |
| 696 bool bIsStrokeRect = fBorderWidth > 0; | |
| 697 | |
| 698 if (bIsStrokeRect) { | |
| 699 sAppStream << fBorderWidth << " w "; | |
| 700 sAppStream << GetDashPatternString(*pAnnotDict); | |
| 701 } | |
| 702 | |
| 703 CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); | |
| 704 rect.Normalize(); | |
| 705 | |
| 706 if (bIsStrokeRect) { | |
| 707 // Deflating rect because stroking a path entails painting all points whose | |
| 708 // perpendicular distance from the path in user space is less than or equal | |
| 709 // to half the line width. | |
| 710 rect.Deflate(fBorderWidth / 2, fBorderWidth / 2); | |
| 711 } | |
| 712 | |
| 713 bool bIsFillRect = pInteriorColor && (pInteriorColor->GetCount() > 0); | |
| 714 | |
| 715 sAppStream << rect.left << " " << rect.bottom << " " << rect.Width() << " " | |
| 716 << rect.Height() << " re " | |
| 717 << GetPaintOperatorString(bIsStrokeRect, bIsFillRect) << "\n"; | |
| 718 | |
| 719 CPDF_Dictionary* pExtGStateDict = | |
| 720 GenerateExtGStateDict(*pAnnotDict, sExtGSDictName, "Normal"); | |
| 721 GenerateAndSetAPDict(pDoc, pAnnotDict, sAppStream, pExtGStateDict); | |
| 722 return true; | |
| 723 } | |
| 724 | |
| 622 bool CPVT_GenerateAP::GenerateSquigglyAP(CPDF_Document* pDoc, | 725 bool CPVT_GenerateAP::GenerateSquigglyAP(CPDF_Document* pDoc, |
| 623 CPDF_Dictionary* pAnnotDict) { | 726 CPDF_Dictionary* pAnnotDict) { |
| 624 // If AP dictionary exists, we use the appearance defined in the | 727 // If AP dictionary exists, we use the appearance defined in the |
| 625 // existing AP dictionary. | 728 // existing AP dictionary. |
| 626 if (pAnnotDict->KeyExist("AP")) | 729 if (pAnnotDict->KeyExist("AP")) |
| 627 return false; | 730 return false; |
| 628 | 731 |
| 629 CFX_ByteTextBuf sAppStream; | 732 CFX_ByteTextBuf sAppStream; |
| 630 CFX_ByteString sExtGSDictName = "GS"; | 733 CFX_ByteString sExtGSDictName = "GS"; |
| 631 sAppStream << "/" << sExtGSDictName << " gs "; | 734 sAppStream << "/" << sExtGSDictName << " gs "; |
| 632 | 735 |
| 633 sAppStream << GetColorStringWithDefault(pAnnotDict, | 736 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayBy("C"), |
| 634 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), | 737 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), |
| 635 PaintOperation::STROKE); | 738 PaintOperation::STROKE); |
| 636 | 739 |
| 637 CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); | 740 CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); |
| 638 rect.Normalize(); | 741 rect.Normalize(); |
| 639 | 742 |
| 640 FX_FLOAT fLineWidth = 1.0; | 743 FX_FLOAT fLineWidth = 1.0; |
| 641 sAppStream << fLineWidth << " w "; | 744 sAppStream << fLineWidth << " w "; |
| 642 | 745 |
| 643 const FX_FLOAT fDelta = 2.0; | 746 const FX_FLOAT fDelta = 2.0; |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 674 CPDF_Dictionary* pAnnotDict) { | 777 CPDF_Dictionary* pAnnotDict) { |
| 675 // If AP dictionary exists, we use the appearance defined in the | 778 // If AP dictionary exists, we use the appearance defined in the |
| 676 // existing AP dictionary. | 779 // existing AP dictionary. |
| 677 if (pAnnotDict->KeyExist("AP")) | 780 if (pAnnotDict->KeyExist("AP")) |
| 678 return false; | 781 return false; |
| 679 | 782 |
| 680 CFX_ByteTextBuf sAppStream; | 783 CFX_ByteTextBuf sAppStream; |
| 681 CFX_ByteString sExtGSDictName = "GS"; | 784 CFX_ByteString sExtGSDictName = "GS"; |
| 682 sAppStream << "/" << sExtGSDictName << " gs "; | 785 sAppStream << "/" << sExtGSDictName << " gs "; |
| 683 | 786 |
| 684 sAppStream << GetColorStringWithDefault(pAnnotDict, | 787 sAppStream << GetColorStringWithDefault(pAnnotDict->GetArrayBy("C"), |
| 685 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), | 788 CPVT_Color(CPVT_Color::kRGB, 0, 0, 0), |
| 686 PaintOperation::STROKE); | 789 PaintOperation::STROKE); |
| 687 | 790 |
| 688 CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); | 791 CFX_FloatRect rect = pAnnotDict->GetRectBy("Rect"); |
| 689 rect.Normalize(); | 792 rect.Normalize(); |
| 690 | 793 |
| 691 FX_FLOAT fLineWidth = 1.0; | 794 FX_FLOAT fLineWidth = 1.0; |
| 692 FX_FLOAT fY = (rect.top + rect.bottom) / 2; | 795 FX_FLOAT fY = (rect.top + rect.bottom) / 2; |
| 693 sAppStream << fLineWidth << " w " << rect.left << " " << fY << " m " | 796 sAppStream << fLineWidth << " w " << rect.left << " " << fY << " m " |
| 694 << rect.right << " " << fY << " l S\n"; | 797 << rect.right << " " << fY << " l S\n"; |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 960 int32_t nFontIndex, | 1063 int32_t nFontIndex, |
| 961 FX_FLOAT fFontSize) { | 1064 FX_FLOAT fFontSize) { |
| 962 CFX_ByteTextBuf sRet; | 1065 CFX_ByteTextBuf sRet; |
| 963 if (pFontMap) { | 1066 if (pFontMap) { |
| 964 CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex); | 1067 CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex); |
| 965 if (sFontAlias.GetLength() > 0 && fFontSize > 0) | 1068 if (sFontAlias.GetLength() > 0 && fFontSize > 0) |
| 966 sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n"; | 1069 sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n"; |
| 967 } | 1070 } |
| 968 return sRet.MakeString(); | 1071 return sRet.MakeString(); |
| 969 } | 1072 } |
| OLD | NEW |