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 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 result.setStrokeWidth(width); | 78 result.setStrokeWidth(width); |
79 } | 79 } |
80 return result; | 80 return result; |
81 } | 81 } |
82 | 82 |
83 SkPDFDevice::GraphicStateEntry::GraphicStateEntry() | 83 SkPDFDevice::GraphicStateEntry::GraphicStateEntry() |
84 : fColor(SK_ColorBLACK) | 84 : fColor(SK_ColorBLACK) |
85 , fTextScaleX(SK_Scalar1) | 85 , fTextScaleX(SK_Scalar1) |
86 , fTextFill(SkPaint::kFill_Style) | 86 , fTextFill(SkPaint::kFill_Style) |
87 , fShaderIndex(-1) | 87 , fShaderIndex(-1) |
88 , fGraphicStateIndex(-1) | 88 , fGraphicStateIndex(-1) { |
89 , fFont(nullptr) | |
90 , fTextSize(SK_ScalarNaN) { | |
91 fMatrix.reset(); | 89 fMatrix.reset(); |
92 } | 90 } |
93 | 91 |
94 bool SkPDFDevice::GraphicStateEntry::compareInitialState( | 92 bool SkPDFDevice::GraphicStateEntry::compareInitialState( |
95 const GraphicStateEntry& cur) { | 93 const GraphicStateEntry& cur) { |
96 return fColor == cur.fColor && | 94 return fColor == cur.fColor && |
97 fShaderIndex == cur.fShaderIndex && | 95 fShaderIndex == cur.fShaderIndex && |
98 fGraphicStateIndex == cur.fGraphicStateIndex && | 96 fGraphicStateIndex == cur.fGraphicStateIndex && |
99 fMatrix == cur.fMatrix && | 97 fMatrix == cur.fMatrix && |
100 fClipStack == cur.fClipStack && | 98 fClipStack == cur.fClipStack && |
(...skipping 753 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
854 | 852 |
855 namespace { | 853 namespace { |
856 class GlyphPositioner { | 854 class GlyphPositioner { |
857 public: | 855 public: |
858 GlyphPositioner(SkDynamicMemoryWStream* content, | 856 GlyphPositioner(SkDynamicMemoryWStream* content, |
859 SkScalar textSkewX, | 857 SkScalar textSkewX, |
860 bool wideChars, | 858 bool wideChars, |
861 bool defaultPositioning, | 859 bool defaultPositioning, |
862 SkPoint origin) | 860 SkPoint origin) |
863 : fContent(content) | 861 : fContent(content) |
864 , fCurrentMatrixOrigin{0.0f, 0.0f} | 862 , fCurrentMatrixOrigin(origin) |
865 , fXAdvance(0.0f) | 863 , fTextSkewX(textSkewX) |
866 , fWideChars(wideChars) | 864 , fWideChars(wideChars) |
867 , fInText(false) | |
868 , fDefaultPositioning(defaultPositioning) { | 865 , fDefaultPositioning(defaultPositioning) { |
869 // Flip the text about the x-axis to account for origin swap and include | |
870 // the passed parameters. | |
871 fContent->writeText("1 0 "); | |
872 SkPDFUtils::AppendScalar(0 - textSkewX, fContent); | |
873 fContent->writeText(" -1 "); | |
874 SkPDFUtils::AppendScalar(origin.x(), fContent); | |
875 fContent->writeText(" "); | |
876 SkPDFUtils::AppendScalar(origin.y(), fContent); | |
877 fContent->writeText(" Tm\n"); | |
878 } | 866 } |
879 ~GlyphPositioner() { this->flush(); } | 867 ~GlyphPositioner() { this->flush(); } |
880 void flush() { | 868 void flush() { |
881 if (fInText) { | 869 if (fInText) { |
882 fContent->writeText("> Tj\n"); | 870 fContent->writeText("> Tj\n"); |
883 fInText = false; | 871 fInText = false; |
884 } | 872 } |
885 } | 873 } |
886 void setWideChars(bool wideChars) { | |
887 if (fWideChars != wideChars) { | |
888 SkASSERT(!fInText); | |
889 SkASSERT(fWideChars == wideChars); | |
890 fWideChars = wideChars; | |
891 } | |
892 } | |
893 void writeGlyph(SkPoint xy, | 874 void writeGlyph(SkPoint xy, |
894 SkScalar advanceWidth, | 875 SkScalar advanceWidth, |
895 uint16_t glyph) { | 876 uint16_t glyph) { |
| 877 if (!fInitialized) { |
| 878 // Flip the text about the x-axis to account for origin swap and inc
lude |
| 879 // the passed parameters. |
| 880 fContent->writeText("1 0 "); |
| 881 SkPDFUtils::AppendScalar(-fTextSkewX, fContent); |
| 882 fContent->writeText(" -1 "); |
| 883 SkPDFUtils::AppendScalar(fCurrentMatrixOrigin.x(), fContent); |
| 884 fContent->writeText(" "); |
| 885 SkPDFUtils::AppendScalar(fCurrentMatrixOrigin.y(), fContent); |
| 886 fContent->writeText(" Tm\n"); |
| 887 fCurrentMatrixOrigin.set(0.0f, 0.0f); |
| 888 fInitialized = true; |
| 889 } |
896 if (!fDefaultPositioning) { | 890 if (!fDefaultPositioning) { |
897 SkPoint position = xy - fCurrentMatrixOrigin; | 891 SkPoint position = xy - fCurrentMatrixOrigin; |
898 if (position != SkPoint{fXAdvance, 0}) { | 892 if (position != SkPoint{fXAdvance, 0}) { |
899 this->flush(); | 893 this->flush(); |
900 SkPDFUtils::AppendScalar(position.x(), fContent); | 894 SkPDFUtils::AppendScalar(position.x(), fContent); |
901 fContent->writeText(" "); | 895 fContent->writeText(" "); |
902 SkPDFUtils::AppendScalar(-position.y(), fContent); | 896 SkPDFUtils::AppendScalar(-position.y(), fContent); |
903 fContent->writeText(" Td "); | 897 fContent->writeText(" Td "); |
904 fCurrentMatrixOrigin = xy; | 898 fCurrentMatrixOrigin = xy; |
905 fXAdvance = 0; | 899 fXAdvance = 0; |
906 } | 900 } |
907 fXAdvance += advanceWidth; | 901 fXAdvance += advanceWidth; |
908 } | 902 } |
909 if (!fInText) { | 903 if (!fInText) { |
910 fContent->writeText("<"); | 904 fContent->writeText("<"); |
911 fInText = true; | 905 fInText = true; |
912 } | 906 } |
913 if (fWideChars) { | 907 if (fWideChars) { |
914 SkPDFUtils::WriteUInt16BE(fContent, glyph); | 908 SkPDFUtils::WriteUInt16BE(fContent, glyph); |
915 } else { | 909 } else { |
916 SkASSERT(0 == glyph >> 8); | 910 SkASSERT(0 == glyph >> 8); |
917 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph)); | 911 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph)); |
918 } | 912 } |
919 } | 913 } |
920 | 914 |
921 private: | 915 private: |
922 SkDynamicMemoryWStream* fContent; | 916 SkDynamicMemoryWStream* fContent; |
923 SkPoint fCurrentMatrixOrigin; | 917 SkPoint fCurrentMatrixOrigin; |
924 SkScalar fXAdvance; | 918 SkScalar fXAdvance = 0.0f; |
| 919 SkScalar fTextSkewX; |
925 bool fWideChars; | 920 bool fWideChars; |
926 bool fInText; | 921 bool fInText = false; |
| 922 bool fInitialized = false; |
927 const bool fDefaultPositioning; | 923 const bool fDefaultPositioning; |
928 }; | 924 }; |
929 } // namespace | 925 } // namespace |
930 | 926 |
931 static void draw_transparent_text(SkPDFDevice* device, | 927 static void draw_transparent_text(SkPDFDevice* device, |
932 const SkDraw& d, | 928 const SkDraw& d, |
933 const void* text, size_t len, | 929 const void* text, size_t len, |
934 SkScalar x, SkScalar y, | 930 SkScalar x, SkScalar y, |
935 const SkPaint& srcPaint) { | 931 const SkPaint& srcPaint) { |
936 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault(); | 932 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault(); |
(...skipping 25 matching lines...) Expand all Loading... |
962 case SkPaint::kUTF16_TextEncoding: | 958 case SkPaint::kUTF16_TextEncoding: |
963 case SkPaint::kUTF32_TextEncoding: | 959 case SkPaint::kUTF32_TextEncoding: |
964 transparent.setTextEncoding(srcPaint.getTextEncoding()); | 960 transparent.setTextEncoding(srcPaint.getTextEncoding()); |
965 device->drawText(d, text, len, x, y, transparent); | 961 device->drawText(d, text, len, x, y, transparent); |
966 break; | 962 break; |
967 default: | 963 default: |
968 SkFAIL("unknown text encoding"); | 964 SkFAIL("unknown text encoding"); |
969 } | 965 } |
970 } | 966 } |
971 | 967 |
| 968 static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) { |
| 969 wStream->writeText("/"); |
| 970 char prefix = SkPDFResourceDict::GetResourceTypePrefix(SkPDFResourceDict::kF
ont_ResourceType); |
| 971 wStream->write(&prefix, 1); |
| 972 wStream->writeDecAsText(fontIndex); |
| 973 wStream->writeText(" "); |
| 974 SkPDFUtils::AppendScalar(textSize, wStream); |
| 975 wStream->writeText(" Tf\n"); |
| 976 } |
| 977 |
972 void SkPDFDevice::internalDrawText( | 978 void SkPDFDevice::internalDrawText( |
973 const SkDraw& d, const void* sourceText, size_t sourceByteCount, | 979 const SkDraw& d, const void* sourceText, size_t sourceByteCount, |
974 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, | 980 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, |
975 SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters, | 981 SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters, |
976 uint32_t textByteLength, const char* utf8Text) { | 982 uint32_t textByteLength, const char* utf8Text) { |
977 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); | 983 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); |
978 if (srcPaint.getMaskFilter() != nullptr) { | 984 if (srcPaint.getMaskFilter() != nullptr) { |
979 // Don't pretend we support drawing MaskFilters, it makes for artifacts | 985 // Don't pretend we support drawing MaskFilters, it makes for artifacts |
980 // making text unreadable (e.g. same text twice when using CSS shadows). | 986 // making text unreadable (e.g. same text twice when using CSS shadows). |
981 return; | 987 return; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1060 } | 1066 } |
1061 offset.offset(alignmentFactor * advance, 0); | 1067 offset.offset(alignmentFactor * advance, 0); |
1062 } | 1068 } |
1063 ScopedContentEntry content(this, d, paint, true); | 1069 ScopedContentEntry content(this, d, paint, true); |
1064 if (!content.entry()) { | 1070 if (!content.entry()) { |
1065 return; | 1071 return; |
1066 } | 1072 } |
1067 SkDynamicMemoryWStream* out = &content.entry()->fContent; | 1073 SkDynamicMemoryWStream* out = &content.entry()->fContent; |
1068 SkScalar textSize = paint.getTextSize(); | 1074 SkScalar textSize = paint.getTextSize(); |
1069 | 1075 |
1070 int index = 0; | |
1071 while (glyphs[index] > maxGlyphID) { // Invalid glyphID for this font. | |
1072 ++index; // Skip this glyphID | |
1073 if (index == glyphCount) { | |
1074 return; // all glyphIDs were bad. | |
1075 } | |
1076 } | |
1077 | |
1078 out->writeText("BT\n"); | 1076 out->writeText("BT\n"); |
1079 SK_AT_SCOPE_EXIT(out->writeText("ET\n")); | 1077 SK_AT_SCOPE_EXIT(out->writeText("ET\n")); |
1080 | 1078 |
1081 SkPDFFont* font = this->updateFont( | 1079 bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics))
; |
1082 typeface, textSize, glyphs[index], content.entry()); | |
1083 SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met
. | |
1084 if (!font) { return; } | |
1085 | |
1086 GlyphPositioner glyphPositioner(out, | 1080 GlyphPositioner glyphPositioner(out, |
1087 paint.getTextSkewX(), | 1081 paint.getTextSkewX(), |
1088 font->multiByteGlyphs(), | 1082 multiByteGlyphs, |
1089 defaultPositioning, | 1083 defaultPositioning, |
1090 offset); | 1084 offset); |
1091 | 1085 SkPDFFont* font = nullptr; |
1092 while (index < glyphCount) { | 1086 for (int index = 0; index < glyphCount; ++index) { |
1093 int stretch = font->countStretch(&glyphs[index], glyphCount - index, max
GlyphID); | 1087 SkGlyphID gid = glyphs[index]; |
1094 SkASSERT(index + stretch <= glyphCount); | 1088 if (gid > maxGlyphID) { |
1095 if (stretch < 1) { | 1089 continue; // Skip this invalid glyphID. |
1096 // The current pdf font cannot encode the next glyph. | 1090 } |
1097 // Try to get a pdf font which can encode the next glyph. | 1091 if (!font || !font->hasGlyph(gid)) { |
| 1092 // Either this is the first loop iteration or the current |
| 1093 // PDFFont cannot encode this glyph. |
1098 glyphPositioner.flush(); | 1094 glyphPositioner.flush(); |
1099 // first, validate the next glyph | 1095 // Try to get a font which can encode the glyph. |
1100 while (glyphs[index] > maxGlyphID) { | 1096 int fontIndex = this->getFontResourceIndex(typeface, gid); |
1101 ++index; // Skip this glyphID | 1097 SkASSERT(fontIndex >= 0); |
1102 if (index == glyphCount) { | 1098 if (fontIndex < 0) { return; } |
1103 return; // all remainng glyphIDs were bad. | 1099 update_font(out, fontIndex, textSize); |
1104 } | 1100 font = fFontResources[fontIndex]; |
1105 } | 1101 SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource
are met. |
1106 SkASSERT(index < glyphCount); | |
1107 font = this->updateFont(typeface, textSize, glyphs[index], content.e
ntry()); | |
1108 SkASSERT(font); // preconditions for SkPDFFont::GetFontResource met
. | |
1109 if (!font) { return; } | 1102 if (!font) { return; } |
1110 glyphPositioner.setWideChars(font->multiByteGlyphs()); | 1103 SkASSERT(font->multiByteGlyphs() == multiByteGlyphs); |
1111 // Get stretch for this new font. | 1104 } |
1112 stretch = font->countStretch(&glyphs[index], glyphCount - index, max
GlyphID); | 1105 font->noteGlyphUsage(gid); |
1113 if (stretch < 1) { | 1106 SkScalar advance{0.0f}; |
1114 SkDEBUGFAIL("PDF could not encode glyph."); | 1107 SkPoint xy{0.0f, 0.0f}; |
1115 return; | 1108 if (!defaultPositioning) { |
| 1109 advance = glyphCache->getGlyphIDAdvance(gid).fAdvanceX; |
| 1110 xy = SkTextBlob::kFull_Positioning == positioning |
| 1111 ? SkPoint{pos[2 * index], pos[2 * index + 1]} |
| 1112 : SkPoint{pos[index], 0}; |
| 1113 if (alignment != SkPaint::kLeft_Align) { |
| 1114 xy.offset(alignmentFactor * advance, 0); |
1116 } | 1115 } |
1117 } | 1116 } |
1118 while (stretch-- > 0) { | 1117 SkGlyphID encodedGlyph = |
1119 SkGlyphID gid = glyphs[index]; | 1118 multiByteGlyphs ? gid : font->glyphToPDFFontEncoding(gid); |
1120 if (gid <= maxGlyphID) { | 1119 glyphPositioner.writeGlyph(xy, advance, encodedGlyph); |
1121 font->noteGlyphUsage(gid); | |
1122 SkGlyphID encodedGlyph = font->glyphToPDFFontEncoding(gid); | |
1123 if (defaultPositioning) { | |
1124 glyphPositioner.writeGlyph(SkPoint{0, 0}, 0, encodedGlyph); | |
1125 } else { | |
1126 SkScalar advance = glyphCache->getGlyphIDAdvance(gid).fAdvan
ceX; | |
1127 SkPoint xy = SkTextBlob::kFull_Positioning == positioning | |
1128 ? SkPoint{pos[2 * index], pos[2 * index + 1]} | |
1129 : SkPoint{pos[index], 0}; | |
1130 if (alignment != SkPaint::kLeft_Align) { | |
1131 xy.offset(alignmentFactor * advance, 0); | |
1132 } | |
1133 glyphPositioner.writeGlyph(xy, advance, encodedGlyph); | |
1134 } | |
1135 } | |
1136 ++index; | |
1137 } | |
1138 } | 1120 } |
1139 } | 1121 } |
1140 | 1122 |
1141 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, | 1123 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, |
1142 SkScalar x, SkScalar y, const SkPaint& paint) { | 1124 SkScalar x, SkScalar y, const SkPaint& paint) { |
1143 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni
ng, | 1125 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni
ng, |
1144 SkPoint{x, y}, paint, nullptr, 0, nullptr); | 1126 SkPoint{x, y}, paint, nullptr, 0, nullptr); |
1145 } | 1127 } |
1146 | 1128 |
1147 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, | 1129 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, |
(...skipping 682 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1830 // Assumes that xobject has been canonicalized (so we can directly compare | 1812 // Assumes that xobject has been canonicalized (so we can directly compare |
1831 // pointers). | 1813 // pointers). |
1832 int result = fXObjectResources.find(xObject); | 1814 int result = fXObjectResources.find(xObject); |
1833 if (result < 0) { | 1815 if (result < 0) { |
1834 result = fXObjectResources.count(); | 1816 result = fXObjectResources.count(); |
1835 fXObjectResources.push(SkRef(xObject)); | 1817 fXObjectResources.push(SkRef(xObject)); |
1836 } | 1818 } |
1837 return result; | 1819 return result; |
1838 } | 1820 } |
1839 | 1821 |
1840 SkPDFFont* SkPDFDevice::updateFont(SkTypeface* typeface, | |
1841 SkScalar textSize, | |
1842 uint16_t glyphID, | |
1843 SkPDFDevice::ContentEntry* contentEntry) { | |
1844 if (contentEntry->fState.fFont == nullptr || | |
1845 contentEntry->fState.fTextSize != textSize || | |
1846 !contentEntry->fState.fFont->hasGlyph(glyphID)) { | |
1847 int fontIndex = getFontResourceIndex(typeface, glyphID); | |
1848 if (fontIndex < 0) { | |
1849 SkDebugf("SkPDF: Font error."); | |
1850 return nullptr; | |
1851 } | |
1852 contentEntry->fContent.writeText("/"); | |
1853 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName( | |
1854 SkPDFResourceDict::kFont_ResourceType, | |
1855 fontIndex).c_str()); | |
1856 contentEntry->fContent.writeText(" "); | |
1857 SkPDFUtils::AppendScalar(textSize, &contentEntry->fContent); | |
1858 contentEntry->fContent.writeText(" Tf\n"); | |
1859 contentEntry->fState.fFont = fFontResources[fontIndex]; | |
1860 } | |
1861 return contentEntry->fState.fFont; | |
1862 } | |
1863 | |
1864 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { | 1822 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { |
1865 sk_sp<SkPDFFont> newFont( | 1823 sk_sp<SkPDFFont> newFont( |
1866 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID)); | 1824 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID)); |
1867 if (!newFont) { | 1825 if (!newFont) { |
1868 return -1; | 1826 return -1; |
1869 } | 1827 } |
1870 int resourceIndex = fFontResources.find(newFont.get()); | 1828 int resourceIndex = fFontResources.find(newFont.get()); |
1871 if (resourceIndex < 0) { | 1829 if (resourceIndex < 0) { |
1872 fDocument->registerFont(newFont.get()); | 1830 fDocument->registerFont(newFont.get()); |
1873 resourceIndex = fFontResources.count(); | 1831 resourceIndex = fFontResources.count(); |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2081 } | 2039 } |
2082 | 2040 |
2083 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { | 2041 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { |
2084 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), | 2042 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), |
2085 image->makeNonTextureImage()); | 2043 image->makeNonTextureImage()); |
2086 } | 2044 } |
2087 | 2045 |
2088 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { | 2046 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { |
2089 return nullptr; | 2047 return nullptr; |
2090 } | 2048 } |
OLD | NEW |