OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkPDFDevice.h" | 8 #include "SkPDFDevice.h" |
9 #include "SkAnnotationKeys.h" | 9 #include "SkAnnotationKeys.h" |
10 #include "SkBitmapDevice.h" | 10 #include "SkBitmapDevice.h" |
(...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
620 * devices have rectangular shape. | 620 * devices have rectangular shape. |
621 */ | 621 */ |
622 void setShape(const SkPath& shape) { | 622 void setShape(const SkPath& shape) { |
623 fShape = shape; | 623 fShape = shape; |
624 } | 624 } |
625 | 625 |
626 private: | 626 private: |
627 SkPDFDevice* fDevice; | 627 SkPDFDevice* fDevice; |
628 SkPDFDevice::ContentEntry* fContentEntry; | 628 SkPDFDevice::ContentEntry* fContentEntry; |
629 SkXfermode::Mode fXfermode; | 629 SkXfermode::Mode fXfermode; |
630 SkPDFFormXObject* fDstFormXObject; | 630 SkPDFObject* fDstFormXObject; |
631 SkPath fShape; | 631 SkPath fShape; |
632 | 632 |
633 void init(const SkClipStack* clipStack, const SkRegion& clipRegion, | 633 void init(const SkClipStack* clipStack, const SkRegion& clipRegion, |
634 const SkMatrix& matrix, const SkPaint& paint, bool hasText) { | 634 const SkMatrix& matrix, const SkPaint& paint, bool hasText) { |
635 // Shape has to be flatten before we get here. | 635 // Shape has to be flatten before we get here. |
636 if (matrix.hasPerspective()) { | 636 if (matrix.hasPerspective()) { |
637 NOT_IMPLEMENTED(!matrix.hasPerspective(), false); | 637 NOT_IMPLEMENTED(!matrix.hasPerspective(), false); |
638 return; | 638 return; |
639 } | 639 } |
640 if (paint.getXfermode()) { | 640 if (paint.getXfermode()) { |
(...skipping 746 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1387 SkPath shape; | 1387 SkPath shape; |
1388 shape.addRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y), | 1388 shape.addRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y), |
1389 SkIntToScalar(device->width()), | 1389 SkIntToScalar(device->width()), |
1390 SkIntToScalar(device->height()))); | 1390 SkIntToScalar(device->height()))); |
1391 content.setShape(shape); | 1391 content.setShape(shape); |
1392 } | 1392 } |
1393 if (!content.needSource()) { | 1393 if (!content.needSource()) { |
1394 return; | 1394 return; |
1395 } | 1395 } |
1396 | 1396 |
1397 auto xObject = sk_make_sp<SkPDFFormXObject>(pdfDevice); | 1397 auto xObject = pdfDevice->makeFormXObjectFromDevice(); |
1398 SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()), | 1398 SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()), |
1399 &content.entry()->fContent); | 1399 &content.entry()->fContent); |
1400 } | 1400 } |
1401 | 1401 |
1402 SkImageInfo SkPDFDevice::imageInfo() const { | 1402 SkImageInfo SkPDFDevice::imageInfo() const { |
1403 SkImageInfo info = SkImageInfo::MakeUnknown(fPageSize.width(), fPageSize.hei ght()); | 1403 SkImageInfo info = SkImageInfo::MakeUnknown(fPageSize.width(), fPageSize.hei ght()); |
1404 return info; | 1404 return info; |
1405 } | 1405 } |
1406 | 1406 |
1407 sk_sp<SkSurface> SkPDFDevice::makeSurface(const SkImageInfo& info, const SkSurfa ceProps& props) { | 1407 sk_sp<SkSurface> SkPDFDevice::makeSurface(const SkImageInfo& info, const SkSurfa ceProps& props) { |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1603 pdfDest->appendName("XYZ"); | 1603 pdfDest->appendName("XYZ"); |
1604 SkPoint p = fInitialTransform.mapXY(dest.point.x(), dest.point.y()); | 1604 SkPoint p = fInitialTransform.mapXY(dest.point.x(), dest.point.y()); |
1605 pdfDest->appendScalar(p.x()); | 1605 pdfDest->appendScalar(p.x()); |
1606 pdfDest->appendScalar(p.y()); | 1606 pdfDest->appendScalar(p.y()); |
1607 pdfDest->appendInt(0); // Leave zoom unchanged | 1607 pdfDest->appendInt(0); // Leave zoom unchanged |
1608 SkString name(static_cast<const char*>(dest.nameData->data())); | 1608 SkString name(static_cast<const char*>(dest.nameData->data())); |
1609 dict->insertObject(name, std::move(pdfDest)); | 1609 dict->insertObject(name, std::move(pdfDest)); |
1610 } | 1610 } |
1611 } | 1611 } |
1612 | 1612 |
1613 SkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() { | 1613 sk_sp<SkPDFObject> SkPDFDevice::makeFormXObjectFromDevice() { |
1614 SkPDFFormXObject* xobject = new SkPDFFormXObject(this); | 1614 auto xobject = SkPDFMakeFormXObject(this->content(), |
1615 this->copyMediaBox(), | |
1616 this->makeResourceDict(), | |
1617 nullptr); | |
tomhudson
2016/07/27 20:30:58
I don't like this because I have to read both forw
hal.canary
2016/07/27 20:41:11
Done.
| |
1615 // We always draw the form xobjects that we create back into the device, so | 1618 // We always draw the form xobjects that we create back into the device, so |
1616 // we simply preserve the font usage instead of pulling it out and merging | 1619 // we simply preserve the font usage instead of pulling it out and merging |
1617 // it back in later. | 1620 // it back in later. |
1618 cleanUp(); // Reset this device to have no content. | 1621 cleanUp(); // Reset this device to have no content. |
1619 init(); | 1622 init(); |
1620 return xobject; | 1623 return xobject; |
1621 } | 1624 } |
1622 | 1625 |
1623 void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex, | 1626 void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex, |
1624 SkPDFFormXObject* mask, | 1627 SkPDFObject* mask, |
1625 const SkClipStack* clipStack, | 1628 const SkClipStack* clipStack, |
1626 const SkRegion& clipRegion, | 1629 const SkRegion& clipRegion, |
1627 SkXfermode::Mode mode, | 1630 SkXfermode::Mode mode, |
1628 bool invertClip) { | 1631 bool invertClip) { |
1629 if (clipRegion.isEmpty() && !invertClip) { | 1632 if (clipRegion.isEmpty() && !invertClip) { |
1630 return; | 1633 return; |
1631 } | 1634 } |
1632 | 1635 |
1633 auto sMaskGS = SkPDFGraphicState::GetSMaskGraphicState( | 1636 auto sMaskGS = SkPDFGraphicState::GetSMaskGraphicState( |
1634 mask, invertClip, SkPDFGraphicState::kAlpha_SMaskMode, fDocument->ca non()); | 1637 mask, invertClip, SkPDFGraphicState::kAlpha_SMaskMode, fDocument->ca non()); |
(...skipping 16 matching lines...) Expand all Loading... | |
1651 sMaskGS = fDocument->canon()->makeNoSmaskGraphicState(); | 1654 sMaskGS = fDocument->canon()->makeNoSmaskGraphicState(); |
1652 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), | 1655 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), |
1653 &content.entry()->fContent); | 1656 &content.entry()->fContent); |
1654 } | 1657 } |
1655 | 1658 |
1656 SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* cli pStack, | 1659 SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* cli pStack, |
1657 const SkRegion& clipRegion, | 1660 const SkRegion& clipRegion, |
1658 const SkMatrix& matrix, | 1661 const SkMatrix& matrix, |
1659 const SkPaint& paint, | 1662 const SkPaint& paint, |
1660 bool hasText, | 1663 bool hasText, |
1661 SkPDFFormXObject** dst) { | 1664 SkPDFObject** dst) { |
1662 *dst = nullptr; | 1665 *dst = nullptr; |
1663 if (clipRegion.isEmpty()) { | 1666 if (clipRegion.isEmpty()) { |
1664 return nullptr; | 1667 return nullptr; |
1665 } | 1668 } |
1666 | 1669 |
1667 // The clip stack can come from an SkDraw where it is technically optional. | 1670 // The clip stack can come from an SkDraw where it is technically optional. |
1668 SkClipStack synthesizedClipStack; | 1671 SkClipStack synthesizedClipStack; |
1669 if (clipStack == nullptr) { | 1672 if (clipStack == nullptr) { |
1670 if (clipRegion == fExistingClipRegion) { | 1673 if (clipRegion == fExistingClipRegion) { |
1671 clipStack = &fExistingClipStack; | 1674 clipStack = &fExistingClipStack; |
(...skipping 20 matching lines...) Expand all Loading... | |
1692 if (xfermode == SkXfermode::kClear_Mode || | 1695 if (xfermode == SkXfermode::kClear_Mode || |
1693 xfermode == SkXfermode::kSrc_Mode || | 1696 xfermode == SkXfermode::kSrc_Mode || |
1694 xfermode == SkXfermode::kSrcIn_Mode || | 1697 xfermode == SkXfermode::kSrcIn_Mode || |
1695 xfermode == SkXfermode::kDstIn_Mode || | 1698 xfermode == SkXfermode::kDstIn_Mode || |
1696 xfermode == SkXfermode::kSrcOut_Mode || | 1699 xfermode == SkXfermode::kSrcOut_Mode || |
1697 xfermode == SkXfermode::kDstOut_Mode || | 1700 xfermode == SkXfermode::kDstOut_Mode || |
1698 xfermode == SkXfermode::kSrcATop_Mode || | 1701 xfermode == SkXfermode::kSrcATop_Mode || |
1699 xfermode == SkXfermode::kDstATop_Mode || | 1702 xfermode == SkXfermode::kDstATop_Mode || |
1700 xfermode == SkXfermode::kModulate_Mode) { | 1703 xfermode == SkXfermode::kModulate_Mode) { |
1701 if (!isContentEmpty()) { | 1704 if (!isContentEmpty()) { |
1702 *dst = createFormXObjectFromDevice(); | 1705 // TODO(halcanary): make this safer. |
1706 *dst = this->makeFormXObjectFromDevice().release(); | |
tomhudson
2016/07/27 20:30:58
Note TODO
hal.canary
2016/07/27 20:41:11
Acknowledged.
| |
1703 SkASSERT(isContentEmpty()); | 1707 SkASSERT(isContentEmpty()); |
1704 } else if (xfermode != SkXfermode::kSrc_Mode && | 1708 } else if (xfermode != SkXfermode::kSrc_Mode && |
1705 xfermode != SkXfermode::kSrcOut_Mode) { | 1709 xfermode != SkXfermode::kSrcOut_Mode) { |
1706 // Except for Src and SrcOut, if there isn't anything already there, | 1710 // Except for Src and SrcOut, if there isn't anything already there, |
1707 // then we're done. | 1711 // then we're done. |
1708 return nullptr; | 1712 return nullptr; |
1709 } | 1713 } |
1710 } | 1714 } |
1711 // TODO(vandebo): Figure out how/if we can handle the following modes: | 1715 // TODO(vandebo): Figure out how/if we can handle the following modes: |
1712 // Xor, Plus. | 1716 // Xor, Plus. |
(...skipping 10 matching lines...) Expand all Loading... | |
1723 entry = fContentEntries.emplace_back(); | 1727 entry = fContentEntries.emplace_back(); |
1724 } else { | 1728 } else { |
1725 entry = fContentEntries.emplace_front(); | 1729 entry = fContentEntries.emplace_front(); |
1726 } | 1730 } |
1727 populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint, | 1731 populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint, |
1728 hasText, &entry->fState); | 1732 hasText, &entry->fState); |
1729 return entry; | 1733 return entry; |
1730 } | 1734 } |
1731 | 1735 |
1732 void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode, | 1736 void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode, |
1733 SkPDFFormXObject* dst, | 1737 SkPDFObject* dst, |
1734 SkPath* shape) { | 1738 SkPath* shape) { |
1735 if (xfermode != SkXfermode::kClear_Mode && | 1739 if (xfermode != SkXfermode::kClear_Mode && |
1736 xfermode != SkXfermode::kSrc_Mode && | 1740 xfermode != SkXfermode::kSrc_Mode && |
1737 xfermode != SkXfermode::kDstOver_Mode && | 1741 xfermode != SkXfermode::kDstOver_Mode && |
1738 xfermode != SkXfermode::kSrcIn_Mode && | 1742 xfermode != SkXfermode::kSrcIn_Mode && |
1739 xfermode != SkXfermode::kDstIn_Mode && | 1743 xfermode != SkXfermode::kDstIn_Mode && |
1740 xfermode != SkXfermode::kSrcOut_Mode && | 1744 xfermode != SkXfermode::kSrcOut_Mode && |
1741 xfermode != SkXfermode::kDstOut_Mode && | 1745 xfermode != SkXfermode::kDstOut_Mode && |
1742 xfermode != SkXfermode::kSrcATop_Mode && | 1746 xfermode != SkXfermode::kSrcATop_Mode && |
1743 xfermode != SkXfermode::kDstATop_Mode && | 1747 xfermode != SkXfermode::kDstATop_Mode && |
(...skipping 24 matching lines...) Expand all Loading... | |
1768 // if source has shape, we need to clip it too, so a copy of the clip is | 1772 // if source has shape, we need to clip it too, so a copy of the clip is |
1769 // saved. | 1773 // saved. |
1770 | 1774 |
1771 SkClipStack clipStack = fContentEntries.front()->fState.fClipStack; | 1775 SkClipStack clipStack = fContentEntries.front()->fState.fClipStack; |
1772 SkRegion clipRegion = fContentEntries.front()->fState.fClipRegion; | 1776 SkRegion clipRegion = fContentEntries.front()->fState.fClipRegion; |
1773 | 1777 |
1774 SkMatrix identity; | 1778 SkMatrix identity; |
1775 identity.reset(); | 1779 identity.reset(); |
1776 SkPaint stockPaint; | 1780 SkPaint stockPaint; |
1777 | 1781 |
1778 sk_sp<SkPDFFormXObject> srcFormXObject; | 1782 sk_sp<SkPDFObject> srcFormXObject; |
1779 if (isContentEmpty()) { | 1783 if (isContentEmpty()) { |
1780 // If nothing was drawn and there's no shape, then the draw was a | 1784 // If nothing was drawn and there's no shape, then the draw was a |
1781 // no-op, but dst needs to be restored for that to be true. | 1785 // no-op, but dst needs to be restored for that to be true. |
1782 // If there is shape, then an empty source with Src, SrcIn, SrcOut, | 1786 // If there is shape, then an empty source with Src, SrcIn, SrcOut, |
1783 // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop | 1787 // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop |
1784 // reduces to Dst. | 1788 // reduces to Dst. |
1785 if (shape == nullptr || xfermode == SkXfermode::kDstOut_Mode || | 1789 if (shape == nullptr || xfermode == SkXfermode::kDstOut_Mode || |
1786 xfermode == SkXfermode::kSrcATop_Mode) { | 1790 xfermode == SkXfermode::kSrcATop_Mode) { |
1787 ScopedContentEntry content(this, &fExistingClipStack, | 1791 ScopedContentEntry content(this, &fExistingClipStack, |
1788 fExistingClipRegion, identity, | 1792 fExistingClipRegion, identity, |
1789 stockPaint); | 1793 stockPaint); |
1790 SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst), | 1794 SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst), |
1791 &content.entry()->fContent); | 1795 &content.entry()->fContent); |
1792 return; | 1796 return; |
1793 } else { | 1797 } else { |
1794 xfermode = SkXfermode::kClear_Mode; | 1798 xfermode = SkXfermode::kClear_Mode; |
1795 } | 1799 } |
1796 } else { | 1800 } else { |
1797 SkASSERT(fContentEntries.count() == 1); | 1801 SkASSERT(fContentEntries.count() == 1); |
1798 srcFormXObject.reset(createFormXObjectFromDevice()); | 1802 srcFormXObject = this->makeFormXObjectFromDevice(); |
1799 } | 1803 } |
1800 | 1804 |
1801 // TODO(vandebo) srcFormXObject may contain alpha, but here we want it | 1805 // TODO(vandebo) srcFormXObject may contain alpha, but here we want it |
1802 // without alpha. | 1806 // without alpha. |
1803 if (xfermode == SkXfermode::kSrcATop_Mode) { | 1807 if (xfermode == SkXfermode::kSrcATop_Mode) { |
1804 // TODO(vandebo): In order to properly support SrcATop we have to track | 1808 // TODO(vandebo): In order to properly support SrcATop we have to track |
1805 // the shape of what's been drawn at all times. It's the intersection of | 1809 // the shape of what's been drawn at all times. It's the intersection of |
1806 // the non-transparent parts of the device and the outlines (shape) of | 1810 // the non-transparent parts of the device and the outlines (shape) of |
1807 // all images and devices drawn. | 1811 // all images and devices drawn. |
1808 drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst, | 1812 drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst, |
1809 &fExistingClipStack, fExistingClipRegion, | 1813 &fExistingClipStack, fExistingClipRegion, |
1810 SkXfermode::kSrcOver_Mode, true); | 1814 SkXfermode::kSrcOver_Mode, true); |
1811 } else { | 1815 } else { |
1812 sk_sp<SkPDFFormXObject> dstMaskStorage; | 1816 sk_sp<SkPDFObject> dstMaskStorage; |
1813 SkPDFFormXObject* dstMask = srcFormXObject.get(); | 1817 SkPDFObject* dstMask = srcFormXObject.get(); |
1814 if (shape != nullptr) { | 1818 if (shape != nullptr) { |
1815 // Draw shape into a form-xobject. | 1819 // Draw shape into a form-xobject. |
1816 SkRasterClip rc(clipRegion); | 1820 SkRasterClip rc(clipRegion); |
1817 SkDraw d; | 1821 SkDraw d; |
1818 d.fMatrix = &identity; | 1822 d.fMatrix = &identity; |
1819 d.fRC = &rc; | 1823 d.fRC = &rc; |
1820 d.fClipStack = &clipStack; | 1824 d.fClipStack = &clipStack; |
1821 SkPaint filledPaint; | 1825 SkPaint filledPaint; |
1822 filledPaint.setColor(SK_ColorBLACK); | 1826 filledPaint.setColor(SK_ColorBLACK); |
1823 filledPaint.setStyle(SkPaint::kFill_Style); | 1827 filledPaint.setStyle(SkPaint::kFill_Style); |
1824 this->drawPath(d, *shape, filledPaint, nullptr, true); | 1828 this->drawPath(d, *shape, filledPaint, nullptr, true); |
1825 | 1829 |
1826 dstMaskStorage.reset(createFormXObjectFromDevice()); | 1830 dstMaskStorage = this->makeFormXObjectFromDevice(); |
1827 dstMask = dstMaskStorage.get(); | 1831 dstMask = dstMaskStorage.get(); |
1828 } | 1832 } |
1829 drawFormXObjectWithMask(addXObjectResource(dst), dstMask, | 1833 drawFormXObjectWithMask(addXObjectResource(dst), dstMask, |
1830 &fExistingClipStack, fExistingClipRegion, | 1834 &fExistingClipStack, fExistingClipRegion, |
1831 SkXfermode::kSrcOver_Mode, true); | 1835 SkXfermode::kSrcOver_Mode, true); |
1832 } | 1836 } |
1833 | 1837 |
1834 if (xfermode == SkXfermode::kClear_Mode) { | 1838 if (xfermode == SkXfermode::kClear_Mode) { |
1835 return; | 1839 return; |
1836 } else if (xfermode == SkXfermode::kSrc_Mode || | 1840 } else if (xfermode == SkXfermode::kSrc_Mode || |
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2241 } | 2245 } |
2242 | 2246 |
2243 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { | 2247 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { |
2244 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), | 2248 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), |
2245 image->makeNonTextureImage()); | 2249 image->makeNonTextureImage()); |
2246 } | 2250 } |
2247 | 2251 |
2248 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { | 2252 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { |
2249 return nullptr; | 2253 return nullptr; |
2250 } | 2254 } |
OLD | NEW |