| 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 | 9 |
| 10 #include "SkAnnotationKeys.h" | 10 #include "SkAnnotationKeys.h" |
| (...skipping 689 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 700 }; | 700 }; |
| 701 | 701 |
| 702 //////////////////////////////////////////////////////////////////////////////// | 702 //////////////////////////////////////////////////////////////////////////////// |
| 703 | 703 |
| 704 SkPDFDevice::SkPDFDevice(SkISize pageSize, SkScalar rasterDpi, SkPDFDocument* do
c, bool flip) | 704 SkPDFDevice::SkPDFDevice(SkISize pageSize, SkScalar rasterDpi, SkPDFDocument* do
c, bool flip) |
| 705 : INHERITED(SkSurfaceProps(0, kUnknown_SkPixelGeometry)) | 705 : INHERITED(SkSurfaceProps(0, kUnknown_SkPixelGeometry)) |
| 706 , fPageSize(pageSize) | 706 , fPageSize(pageSize) |
| 707 , fContentSize(pageSize) | 707 , fContentSize(pageSize) |
| 708 , fExistingClipRegion(SkIRect::MakeSize(pageSize)) | 708 , fExistingClipRegion(SkIRect::MakeSize(pageSize)) |
| 709 , fLastContentEntry(nullptr) | 709 , fLastContentEntry(nullptr) |
| 710 , fLastMarginContentEntry(nullptr) | |
| 711 , fDrawingArea(kContent_DrawingArea) | |
| 712 , fClipStack(nullptr) | 710 , fClipStack(nullptr) |
| 713 , fFontGlyphUsage(new SkPDFGlyphSetMap) | 711 , fFontGlyphUsage(new SkPDFGlyphSetMap) |
| 714 , fRasterDpi(rasterDpi) | 712 , fRasterDpi(rasterDpi) |
| 715 , fDocument(doc) { | 713 , fDocument(doc) { |
| 716 SkASSERT(pageSize.width() > 0); | 714 SkASSERT(pageSize.width() > 0); |
| 717 SkASSERT(pageSize.height() > 0); | 715 SkASSERT(pageSize.height() > 0); |
| 718 fLegacyBitmap.setInfo( | 716 fLegacyBitmap.setInfo( |
| 719 SkImageInfo::MakeUnknown(pageSize.width(), pageSize.height())); | 717 SkImageInfo::MakeUnknown(pageSize.width(), pageSize.height())); |
| 720 if (flip) { | 718 if (flip) { |
| 721 // Skia generally uses the top left as the origin but PDF | 719 // Skia generally uses the top left as the origin but PDF |
| 722 // natively has the origin at the bottom left. This matrix | 720 // natively has the origin at the bottom left. This matrix |
| 723 // corrects for that. But that only needs to be done once, we | 721 // corrects for that. But that only needs to be done once, we |
| 724 // don't do it when layering. | 722 // don't do it when layering. |
| 725 fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight)); | 723 fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight)); |
| 726 fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1); | 724 fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1); |
| 727 } else { | 725 } else { |
| 728 fInitialTransform.setIdentity(); | 726 fInitialTransform.setIdentity(); |
| 729 } | 727 } |
| 730 } | 728 } |
| 731 | 729 |
| 732 SkPDFDevice::~SkPDFDevice() { | 730 SkPDFDevice::~SkPDFDevice() { |
| 733 this->cleanUp(true); | 731 this->cleanUp(true); |
| 734 } | 732 } |
| 735 | 733 |
| 736 void SkPDFDevice::init() { | 734 void SkPDFDevice::init() { |
| 737 fContentEntries.reset(); | 735 fContentEntries.reset(); |
| 738 fLastContentEntry = nullptr; | 736 fLastContentEntry = nullptr; |
| 739 fMarginContentEntries.reset(); | |
| 740 fLastMarginContentEntry = nullptr; | |
| 741 fDrawingArea = kContent_DrawingArea; | |
| 742 if (fFontGlyphUsage.get() == nullptr) { | 737 if (fFontGlyphUsage.get() == nullptr) { |
| 743 fFontGlyphUsage.reset(new SkPDFGlyphSetMap); | 738 fFontGlyphUsage.reset(new SkPDFGlyphSetMap); |
| 744 } | 739 } |
| 745 } | 740 } |
| 746 | 741 |
| 747 void SkPDFDevice::cleanUp(bool clearFontUsage) { | 742 void SkPDFDevice::cleanUp(bool clearFontUsage) { |
| 748 fGraphicStateResources.unrefAll(); | 743 fGraphicStateResources.unrefAll(); |
| 749 fXObjectResources.unrefAll(); | 744 fXObjectResources.unrefAll(); |
| 750 fFontResources.unrefAll(); | 745 fFontResources.unrefAll(); |
| 751 fShaderResources.unrefAll(); | 746 fShaderResources.unrefAll(); |
| (...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1402 void SkPDFDevice::onDetachFromCanvas() { | 1397 void SkPDFDevice::onDetachFromCanvas() { |
| 1403 INHERITED::onDetachFromCanvas(); | 1398 INHERITED::onDetachFromCanvas(); |
| 1404 | 1399 |
| 1405 fClipStack = nullptr; | 1400 fClipStack = nullptr; |
| 1406 } | 1401 } |
| 1407 | 1402 |
| 1408 sk_sp<SkSurface> SkPDFDevice::makeSurface(const SkImageInfo& info, const SkSurfa
ceProps& props) { | 1403 sk_sp<SkSurface> SkPDFDevice::makeSurface(const SkImageInfo& info, const SkSurfa
ceProps& props) { |
| 1409 return SkSurface::MakeRaster(info, &props); | 1404 return SkSurface::MakeRaster(info, &props); |
| 1410 } | 1405 } |
| 1411 | 1406 |
| 1412 ContentEntry* SkPDFDevice::getLastContentEntry() { | |
| 1413 if (fDrawingArea == kContent_DrawingArea) { | |
| 1414 return fLastContentEntry; | |
| 1415 } else { | |
| 1416 return fLastMarginContentEntry; | |
| 1417 } | |
| 1418 } | |
| 1419 | |
| 1420 SkAutoTDelete<ContentEntry>* SkPDFDevice::getContentEntries() { | |
| 1421 if (fDrawingArea == kContent_DrawingArea) { | |
| 1422 return &fContentEntries; | |
| 1423 } else { | |
| 1424 return &fMarginContentEntries; | |
| 1425 } | |
| 1426 } | |
| 1427 | |
| 1428 void SkPDFDevice::setLastContentEntry(ContentEntry* contentEntry) { | |
| 1429 if (fDrawingArea == kContent_DrawingArea) { | |
| 1430 fLastContentEntry = contentEntry; | |
| 1431 } else { | |
| 1432 fLastMarginContentEntry = contentEntry; | |
| 1433 } | |
| 1434 } | |
| 1435 | |
| 1436 void SkPDFDevice::setDrawingArea(DrawingArea drawingArea) { | |
| 1437 // A ScopedContentEntry only exists during the course of a draw call, so | |
| 1438 // this can't be called while a ScopedContentEntry exists. | |
| 1439 fDrawingArea = drawingArea; | |
| 1440 } | |
| 1441 | 1407 |
| 1442 sk_sp<SkPDFDict> SkPDFDevice::makeResourceDict() const { | 1408 sk_sp<SkPDFDict> SkPDFDevice::makeResourceDict() const { |
| 1443 SkTDArray<SkPDFObject*> fonts; | 1409 SkTDArray<SkPDFObject*> fonts; |
| 1444 fonts.setReserve(fFontResources.count()); | 1410 fonts.setReserve(fFontResources.count()); |
| 1445 for (SkPDFFont* font : fFontResources) { | 1411 for (SkPDFFont* font : fFontResources) { |
| 1446 fonts.push(font); | 1412 fonts.push(font); |
| 1447 } | 1413 } |
| 1448 return SkPDFResourceDict::Make( | 1414 return SkPDFResourceDict::Make( |
| 1449 &fGraphicStateResources, | 1415 &fGraphicStateResources, |
| 1450 &fShaderResources, | 1416 &fShaderResources, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1493 entry = entry->fNext.get(); | 1459 entry = entry->fNext.get(); |
| 1494 } | 1460 } |
| 1495 gsState.drainStack(); | 1461 gsState.drainStack(); |
| 1496 } | 1462 } |
| 1497 | 1463 |
| 1498 void SkPDFDevice::writeContent(SkWStream* out) const { | 1464 void SkPDFDevice::writeContent(SkWStream* out) const { |
| 1499 if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) { | 1465 if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) { |
| 1500 SkPDFUtils::AppendTransform(fInitialTransform, out); | 1466 SkPDFUtils::AppendTransform(fInitialTransform, out); |
| 1501 } | 1467 } |
| 1502 | 1468 |
| 1503 // TODO(aayushkumar): Apply clip along the margins. Currently, webkit | |
| 1504 // colors the contentArea white before it starts drawing into it and | |
| 1505 // that currently acts as our clip. | |
| 1506 // Also, think about adding a transform here (or assume that the values | |
| 1507 // sent across account for that) | |
| 1508 SkPDFDevice::copyContentEntriesToData(fMarginContentEntries.get(), out); | |
| 1509 | |
| 1510 // If the content area is the entire page, then we don't need to clip | 1469 // If the content area is the entire page, then we don't need to clip |
| 1511 // the content area (PDF area clips to the page size). Otherwise, | 1470 // the content area (PDF area clips to the page size). Otherwise, |
| 1512 // we have to clip to the content area; we've already applied the | 1471 // we have to clip to the content area; we've already applied the |
| 1513 // initial transform, so just clip to the device size. | 1472 // initial transform, so just clip to the device size. |
| 1514 if (fPageSize != fContentSize) { | 1473 if (fPageSize != fContentSize) { |
| 1515 SkRect r = SkRect::MakeWH(SkIntToScalar(this->width()), | 1474 SkRect r = SkRect::MakeWH(SkIntToScalar(this->width()), |
| 1516 SkIntToScalar(this->height())); | 1475 SkIntToScalar(this->height())); |
| 1517 emit_clip(nullptr, &r, out); | 1476 emit_clip(nullptr, &r, out); |
| 1518 } | 1477 } |
| 1519 | 1478 |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1757 // Xor, Plus. | 1716 // Xor, Plus. |
| 1758 | 1717 |
| 1759 // Dst xfer mode doesn't draw source at all. | 1718 // Dst xfer mode doesn't draw source at all. |
| 1760 if (xfermode == SkXfermode::kDst_Mode) { | 1719 if (xfermode == SkXfermode::kDst_Mode) { |
| 1761 return nullptr; | 1720 return nullptr; |
| 1762 } | 1721 } |
| 1763 | 1722 |
| 1764 ContentEntry* entry; | 1723 ContentEntry* entry; |
| 1765 SkAutoTDelete<ContentEntry> newEntry; | 1724 SkAutoTDelete<ContentEntry> newEntry; |
| 1766 | 1725 |
| 1767 ContentEntry* lastContentEntry = getLastContentEntry(); | 1726 if (fLastContentEntry && fLastContentEntry->fContent.getOffset() == 0) { |
| 1768 if (lastContentEntry && lastContentEntry->fContent.getOffset() == 0) { | 1727 entry = fLastContentEntry; |
| 1769 entry = lastContentEntry; | |
| 1770 } else { | 1728 } else { |
| 1771 newEntry.reset(new ContentEntry); | 1729 newEntry.reset(new ContentEntry); |
| 1772 entry = newEntry.get(); | 1730 entry = newEntry.get(); |
| 1773 } | 1731 } |
| 1774 | 1732 |
| 1775 populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint, | 1733 populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint, |
| 1776 hasText, &entry->fState); | 1734 hasText, &entry->fState); |
| 1777 if (lastContentEntry && xfermode != SkXfermode::kDstOver_Mode && | 1735 if (fLastContentEntry && xfermode != SkXfermode::kDstOver_Mode && |
| 1778 entry->fState.compareInitialState(lastContentEntry->fState)) { | 1736 entry->fState.compareInitialState(fLastContentEntry->fState)) { |
| 1779 return lastContentEntry; | 1737 return fLastContentEntry; |
| 1780 } | 1738 } |
| 1781 | 1739 |
| 1782 SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries(); | 1740 if (!fLastContentEntry) { |
| 1783 if (!lastContentEntry) { | 1741 fContentEntries.reset(entry); |
| 1784 contentEntries->reset(entry); | 1742 fLastContentEntry = entry; |
| 1785 setLastContentEntry(entry); | |
| 1786 } else if (xfermode == SkXfermode::kDstOver_Mode) { | 1743 } else if (xfermode == SkXfermode::kDstOver_Mode) { |
| 1787 entry->fNext.reset(contentEntries->release()); | 1744 entry->fNext.reset(fContentEntries.release()); |
| 1788 contentEntries->reset(entry); | 1745 fContentEntries.reset(entry); |
| 1789 } else { | 1746 } else { |
| 1790 lastContentEntry->fNext.reset(entry); | 1747 fLastContentEntry->fNext.reset(entry); |
| 1791 setLastContentEntry(entry); | 1748 fLastContentEntry = entry; |
| 1792 } | 1749 } |
| 1793 newEntry.release(); | 1750 newEntry.release(); |
| 1794 return entry; | 1751 return entry; |
| 1795 } | 1752 } |
| 1796 | 1753 |
| 1797 void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode, | 1754 void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode, |
| 1798 SkPDFFormXObject* dst, | 1755 SkPDFFormXObject* dst, |
| 1799 SkPath* shape) { | 1756 SkPath* shape) { |
| 1800 if (xfermode != SkXfermode::kClear_Mode && | 1757 if (xfermode != SkXfermode::kClear_Mode && |
| 1801 xfermode != SkXfermode::kSrc_Mode && | 1758 xfermode != SkXfermode::kSrc_Mode && |
| 1802 xfermode != SkXfermode::kDstOver_Mode && | 1759 xfermode != SkXfermode::kDstOver_Mode && |
| 1803 xfermode != SkXfermode::kSrcIn_Mode && | 1760 xfermode != SkXfermode::kSrcIn_Mode && |
| 1804 xfermode != SkXfermode::kDstIn_Mode && | 1761 xfermode != SkXfermode::kDstIn_Mode && |
| 1805 xfermode != SkXfermode::kSrcOut_Mode && | 1762 xfermode != SkXfermode::kSrcOut_Mode && |
| 1806 xfermode != SkXfermode::kDstOut_Mode && | 1763 xfermode != SkXfermode::kDstOut_Mode && |
| 1807 xfermode != SkXfermode::kSrcATop_Mode && | 1764 xfermode != SkXfermode::kSrcATop_Mode && |
| 1808 xfermode != SkXfermode::kDstATop_Mode && | 1765 xfermode != SkXfermode::kDstATop_Mode && |
| 1809 xfermode != SkXfermode::kModulate_Mode) { | 1766 xfermode != SkXfermode::kModulate_Mode) { |
| 1810 SkASSERT(!dst); | 1767 SkASSERT(!dst); |
| 1811 return; | 1768 return; |
| 1812 } | 1769 } |
| 1813 if (xfermode == SkXfermode::kDstOver_Mode) { | 1770 if (xfermode == SkXfermode::kDstOver_Mode) { |
| 1814 SkASSERT(!dst); | 1771 SkASSERT(!dst); |
| 1815 ContentEntry* firstContentEntry = getContentEntries()->get(); | 1772 if (fContentEntries->fContent.getOffset() == 0) { |
| 1816 if (firstContentEntry->fContent.getOffset() == 0) { | |
| 1817 // For DstOver, an empty content entry was inserted before the rest | 1773 // For DstOver, an empty content entry was inserted before the rest |
| 1818 // of the content entries. If nothing was drawn, it needs to be | 1774 // of the content entries. If nothing was drawn, it needs to be |
| 1819 // removed. | 1775 // removed. |
| 1820 SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries(); | 1776 fContentEntries.reset(fContentEntries->fNext.release()); |
| 1821 contentEntries->reset(firstContentEntry->fNext.release()); | |
| 1822 } | 1777 } |
| 1823 return; | 1778 return; |
| 1824 } | 1779 } |
| 1825 if (!dst) { | 1780 if (!dst) { |
| 1826 SkASSERT(xfermode == SkXfermode::kSrc_Mode || | 1781 SkASSERT(xfermode == SkXfermode::kSrc_Mode || |
| 1827 xfermode == SkXfermode::kSrcOut_Mode); | 1782 xfermode == SkXfermode::kSrcOut_Mode); |
| 1828 return; | 1783 return; |
| 1829 } | 1784 } |
| 1830 | 1785 |
| 1831 ContentEntry* contentEntries = getContentEntries()->get(); | |
| 1832 SkASSERT(dst); | 1786 SkASSERT(dst); |
| 1833 SkASSERT(!contentEntries->fNext.get()); | 1787 SkASSERT(!fContentEntries->fNext.get()); |
| 1834 // Changing the current content into a form-xobject will destroy the clip | 1788 // Changing the current content into a form-xobject will destroy the clip |
| 1835 // objects which is fine since the xobject will already be clipped. However | 1789 // objects which is fine since the xobject will already be clipped. However |
| 1836 // if source has shape, we need to clip it too, so a copy of the clip is | 1790 // if source has shape, we need to clip it too, so a copy of the clip is |
| 1837 // saved. | 1791 // saved. |
| 1838 SkClipStack clipStack = contentEntries->fState.fClipStack; | 1792 SkClipStack clipStack = fContentEntries->fState.fClipStack; |
| 1839 SkRegion clipRegion = contentEntries->fState.fClipRegion; | 1793 SkRegion clipRegion = fContentEntries->fState.fClipRegion; |
| 1840 | 1794 |
| 1841 SkMatrix identity; | 1795 SkMatrix identity; |
| 1842 identity.reset(); | 1796 identity.reset(); |
| 1843 SkPaint stockPaint; | 1797 SkPaint stockPaint; |
| 1844 | 1798 |
| 1845 sk_sp<SkPDFFormXObject> srcFormXObject; | 1799 sk_sp<SkPDFFormXObject> srcFormXObject; |
| 1846 if (isContentEmpty()) { | 1800 if (isContentEmpty()) { |
| 1847 // If nothing was drawn and there's no shape, then the draw was a | 1801 // If nothing was drawn and there's no shape, then the draw was a |
| 1848 // no-op, but dst needs to be restored for that to be true. | 1802 // no-op, but dst needs to be restored for that to be true. |
| 1849 // If there is shape, then an empty source with Src, SrcIn, SrcOut, | 1803 // If there is shape, then an empty source with Src, SrcIn, SrcOut, |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1944 SkXfermode::kSrcOver_Mode, false); | 1898 SkXfermode::kSrcOver_Mode, false); |
| 1945 mode = SkXfermode::kMultiply_Mode; | 1899 mode = SkXfermode::kMultiply_Mode; |
| 1946 } | 1900 } |
| 1947 drawFormXObjectWithMask(addXObjectResource(dst), srcFormXObject.get(), | 1901 drawFormXObjectWithMask(addXObjectResource(dst), srcFormXObject.get(), |
| 1948 &fExistingClipStack, fExistingClipRegion, mode, | 1902 &fExistingClipStack, fExistingClipRegion, mode, |
| 1949 xfermode == SkXfermode::kDstOut_Mode); | 1903 xfermode == SkXfermode::kDstOut_Mode); |
| 1950 } | 1904 } |
| 1951 } | 1905 } |
| 1952 | 1906 |
| 1953 bool SkPDFDevice::isContentEmpty() { | 1907 bool SkPDFDevice::isContentEmpty() { |
| 1954 ContentEntry* contentEntries = getContentEntries()->get(); | 1908 if (!fContentEntries || fContentEntries->fContent.getOffset() == 0) { |
| 1955 if (!contentEntries || contentEntries->fContent.getOffset() == 0) { | 1909 SkASSERT(!fContentEntries || !fContentEntries->fNext.get()); |
| 1956 SkASSERT(!contentEntries || !contentEntries->fNext.get()); | |
| 1957 return true; | 1910 return true; |
| 1958 } | 1911 } |
| 1959 return false; | 1912 return false; |
| 1960 } | 1913 } |
| 1961 | 1914 |
| 1962 void SkPDFDevice::populateGraphicStateEntryFromPaint( | 1915 void SkPDFDevice::populateGraphicStateEntryFromPaint( |
| 1963 const SkMatrix& matrix, | 1916 const SkMatrix& matrix, |
| 1964 const SkClipStack& clipStack, | 1917 const SkClipStack& clipStack, |
| 1965 const SkRegion& clipRegion, | 1918 const SkRegion& clipRegion, |
| 1966 const SkPaint& paint, | 1919 const SkPaint& paint, |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2260 if (!pdfimage) { | 2213 if (!pdfimage) { |
| 2261 return; | 2214 return; |
| 2262 } | 2215 } |
| 2263 fDocument->serialize(pdfimage); // serialize images early. | 2216 fDocument->serialize(pdfimage); // serialize images early. |
| 2264 fDocument->canon()->addPDFBitmap(key, pdfimage); | 2217 fDocument->canon()->addPDFBitmap(key, pdfimage); |
| 2265 } | 2218 } |
| 2266 // TODO(halcanary): addXObjectResource() should take a sk_sp<SkPDFObject> | 2219 // TODO(halcanary): addXObjectResource() should take a sk_sp<SkPDFObject> |
| 2267 SkPDFUtils::DrawFormXObject(this->addXObjectResource(pdfimage.get()), | 2220 SkPDFUtils::DrawFormXObject(this->addXObjectResource(pdfimage.get()), |
| 2268 &content.entry()->fContent); | 2221 &content.entry()->fContent); |
| 2269 } | 2222 } |
| OLD | NEW |