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 |