Chromium Code Reviews| 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 |