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 "SkAdvancedTypefaceMetrics.h" |
10 #include "SkAnnotationKeys.h" | 11 #include "SkAnnotationKeys.h" |
11 #include "SkBitmapDevice.h" | 12 #include "SkBitmapDevice.h" |
12 #include "SkBitmapKey.h" | 13 #include "SkBitmapKey.h" |
13 #include "SkColor.h" | 14 #include "SkColor.h" |
14 #include "SkColorFilter.h" | 15 #include "SkColorFilter.h" |
15 #include "SkDraw.h" | 16 #include "SkDraw.h" |
16 #include "SkDrawFilter.h" | 17 #include "SkDrawFilter.h" |
17 #include "SkGlyphCache.h" | 18 #include "SkGlyphCache.h" |
18 #include "SkMakeUnique.h" | 19 #include "SkMakeUnique.h" |
19 #include "SkPath.h" | 20 #include "SkPath.h" |
(...skipping 10 matching lines...) Expand all Loading... |
30 #include "SkPDFTypes.h" | 31 #include "SkPDFTypes.h" |
31 #include "SkPDFUtils.h" | 32 #include "SkPDFUtils.h" |
32 #include "SkRasterClip.h" | 33 #include "SkRasterClip.h" |
33 #include "SkRRect.h" | 34 #include "SkRRect.h" |
34 #include "SkScopeExit.h" | 35 #include "SkScopeExit.h" |
35 #include "SkString.h" | 36 #include "SkString.h" |
36 #include "SkSurface.h" | 37 #include "SkSurface.h" |
37 #include "SkTemplates.h" | 38 #include "SkTemplates.h" |
38 #include "SkTextBlobRunIterator.h" | 39 #include "SkTextBlobRunIterator.h" |
39 #include "SkTextFormatParams.h" | 40 #include "SkTextFormatParams.h" |
| 41 #include "SkUtils.h" |
40 #include "SkXfermodeInterpretation.h" | 42 #include "SkXfermodeInterpretation.h" |
41 | 43 |
42 #define DPI_FOR_RASTER_SCALE_ONE 72 | 44 #define DPI_FOR_RASTER_SCALE_ONE 72 |
43 | 45 |
44 // Utility functions | 46 // Utility functions |
45 | 47 |
46 // If the paint will definitely draw opaquely, replace kSrc_Mode with | 48 // If the paint will definitely draw opaquely, replace kSrc_Mode with |
47 // kSrcOver_Mode. http://crbug.com/473572 | 49 // kSrcOver_Mode. http://crbug.com/473572 |
48 static void replace_srcmode_on_opaque_paint(SkPaint* paint) { | 50 static void replace_srcmode_on_opaque_paint(SkPaint* paint) { |
49 if (kSrcOver_SkXfermodeInterpretation | 51 if (kSrcOver_SkXfermodeInterpretation |
(...skipping 28 matching lines...) Expand all Loading... |
78 result.setStrokeWidth(width); | 80 result.setStrokeWidth(width); |
79 } | 81 } |
80 return result; | 82 return result; |
81 } | 83 } |
82 | 84 |
83 SkPDFDevice::GraphicStateEntry::GraphicStateEntry() | 85 SkPDFDevice::GraphicStateEntry::GraphicStateEntry() |
84 : fColor(SK_ColorBLACK) | 86 : fColor(SK_ColorBLACK) |
85 , fTextScaleX(SK_Scalar1) | 87 , fTextScaleX(SK_Scalar1) |
86 , fTextFill(SkPaint::kFill_Style) | 88 , fTextFill(SkPaint::kFill_Style) |
87 , fShaderIndex(-1) | 89 , fShaderIndex(-1) |
88 , fGraphicStateIndex(-1) | 90 , fGraphicStateIndex(-1) { |
89 , fFont(nullptr) | |
90 , fTextSize(SK_ScalarNaN) { | |
91 fMatrix.reset(); | 91 fMatrix.reset(); |
92 } | 92 } |
93 | 93 |
94 bool SkPDFDevice::GraphicStateEntry::compareInitialState( | 94 bool SkPDFDevice::GraphicStateEntry::compareInitialState( |
95 const GraphicStateEntry& cur) { | 95 const GraphicStateEntry& cur) { |
96 return fColor == cur.fColor && | 96 return fColor == cur.fColor && |
97 fShaderIndex == cur.fShaderIndex && | 97 fShaderIndex == cur.fShaderIndex && |
98 fGraphicStateIndex == cur.fGraphicStateIndex && | 98 fGraphicStateIndex == cur.fGraphicStateIndex && |
99 fMatrix == cur.fMatrix && | 99 fMatrix == cur.fMatrix && |
100 fClipStack == cur.fClipStack && | 100 fClipStack == cur.fClipStack && |
(...skipping 753 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
854 | 854 |
855 namespace { | 855 namespace { |
856 class GlyphPositioner { | 856 class GlyphPositioner { |
857 public: | 857 public: |
858 GlyphPositioner(SkDynamicMemoryWStream* content, | 858 GlyphPositioner(SkDynamicMemoryWStream* content, |
859 SkScalar textSkewX, | 859 SkScalar textSkewX, |
860 bool wideChars, | 860 bool wideChars, |
861 bool defaultPositioning, | 861 bool defaultPositioning, |
862 SkPoint origin) | 862 SkPoint origin) |
863 : fContent(content) | 863 : fContent(content) |
864 , fCurrentMatrixOrigin{0.0f, 0.0f} | 864 , fCurrentMatrixOrigin(origin) |
865 , fXAdvance(0.0f) | 865 , fTextSkewX(textSkewX) |
866 , fWideChars(wideChars) | 866 , fWideChars(wideChars) |
867 , fInText(false) | 867 , fDefaultPositioning(defaultPositioning) {} |
868 , 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 } | |
879 ~GlyphPositioner() { this->flush(); } | 868 ~GlyphPositioner() { this->flush(); } |
880 void flush() { | 869 void flush() { |
881 if (fInText) { | 870 if (fInText) { |
882 fContent->writeText("> Tj\n"); | 871 fContent->writeText("> Tj\n"); |
883 fInText = false; | 872 fInText = false; |
884 } | 873 } |
885 } | 874 } |
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, | 875 void writeGlyph(SkPoint xy, |
894 SkScalar advanceWidth, | 876 SkScalar advanceWidth, |
895 uint16_t glyph) { | 877 uint16_t glyph) { |
| 878 if (!fInitialized) { |
| 879 // Flip the text about the x-axis to account for origin swap and inc
lude |
| 880 // the passed parameters. |
| 881 fContent->writeText("1 0 "); |
| 882 SkPDFUtils::AppendScalar(-fTextSkewX, fContent); |
| 883 fContent->writeText(" -1 "); |
| 884 SkPDFUtils::AppendScalar(fCurrentMatrixOrigin.x(), fContent); |
| 885 fContent->writeText(" "); |
| 886 SkPDFUtils::AppendScalar(fCurrentMatrixOrigin.y(), fContent); |
| 887 fContent->writeText(" Tm\n"); |
| 888 fCurrentMatrixOrigin.set(0.0f, 0.0f); |
| 889 fInitialized = true; |
| 890 } |
896 if (!fDefaultPositioning) { | 891 if (!fDefaultPositioning) { |
897 SkPoint position = xy - fCurrentMatrixOrigin; | 892 SkPoint position = xy - fCurrentMatrixOrigin; |
898 if (position != SkPoint{fXAdvance, 0}) { | 893 if (position != SkPoint{fXAdvance, 0}) { |
899 this->flush(); | 894 this->flush(); |
900 SkPDFUtils::AppendScalar(position.x(), fContent); | 895 SkPDFUtils::AppendScalar(position.x(), fContent); |
901 fContent->writeText(" "); | 896 fContent->writeText(" "); |
902 SkPDFUtils::AppendScalar(-position.y(), fContent); | 897 SkPDFUtils::AppendScalar(-position.y(), fContent); |
903 fContent->writeText(" Td "); | 898 fContent->writeText(" Td "); |
904 fCurrentMatrixOrigin = xy; | 899 fCurrentMatrixOrigin = xy; |
905 fXAdvance = 0; | 900 fXAdvance = 0; |
906 } | 901 } |
907 fXAdvance += advanceWidth; | 902 fXAdvance += advanceWidth; |
908 } | 903 } |
909 if (!fInText) { | 904 if (!fInText) { |
910 fContent->writeText("<"); | 905 fContent->writeText("<"); |
911 fInText = true; | 906 fInText = true; |
912 } | 907 } |
913 if (fWideChars) { | 908 if (fWideChars) { |
914 SkPDFUtils::WriteUInt16BE(fContent, glyph); | 909 SkPDFUtils::WriteUInt16BE(fContent, glyph); |
915 } else { | 910 } else { |
916 SkASSERT(0 == glyph >> 8); | 911 SkASSERT(0 == glyph >> 8); |
917 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph)); | 912 SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph)); |
918 } | 913 } |
919 } | 914 } |
920 | 915 |
921 private: | 916 private: |
922 SkDynamicMemoryWStream* fContent; | 917 SkDynamicMemoryWStream* fContent; |
923 SkPoint fCurrentMatrixOrigin; | 918 SkPoint fCurrentMatrixOrigin; |
924 SkScalar fXAdvance; | 919 SkScalar fXAdvance = 0.0f; |
| 920 SkScalar fTextSkewX; |
925 bool fWideChars; | 921 bool fWideChars; |
926 bool fInText; | 922 bool fInText = false; |
| 923 bool fInitialized = false; |
927 const bool fDefaultPositioning; | 924 const bool fDefaultPositioning; |
928 }; | 925 }; |
| 926 |
| 927 class Clusterator { |
| 928 public: |
| 929 Clusterator(size_t glyphCount) |
| 930 : fClusters(nullptr) |
| 931 , fGlyphCount(SkToU32(glyphCount)) |
| 932 , fTextByteLength(0) |
| 933 , fUtf8Text(nullptr) {} |
| 934 Clusterator(const uint32_t* clusters, |
| 935 size_t glyphCount, |
| 936 uint32_t textByteLength, |
| 937 const char* utf8Text) |
| 938 : fClusters(clusters) |
| 939 , fGlyphCount(SkToU32(glyphCount)) |
| 940 , fTextByteLength(textByteLength) |
| 941 , fUtf8Text(utf8Text) {} |
| 942 struct Cluster { |
| 943 const char* fUtf8Text; |
| 944 uint32_t fTextByteLength; |
| 945 uint32_t fGlyphIndex; |
| 946 uint32_t fGlyphCount; |
| 947 explicit operator bool() const { return fGlyphCount != 0; } |
| 948 }; |
| 949 Cluster next() { |
| 950 if (!fUtf8Text || !fClusters) { |
| 951 // These glyphs have no text. Treat as one "cluster". |
| 952 uint32_t glyphCount = fGlyphCount; |
| 953 fGlyphCount = 0; |
| 954 return Cluster{nullptr, 0, 0, glyphCount}; |
| 955 } |
| 956 if (fGlyphCount == 0 || fTextByteLength == 0) { |
| 957 return Cluster{nullptr, 0, 0, 0}; // empty |
| 958 } |
| 959 uint32_t cluster = fClusters[0]; |
| 960 if (cluster >= fTextByteLength) { |
| 961 return Cluster{nullptr, 0, 0, 0}; // bad input. |
| 962 } |
| 963 uint32_t glyphsInCluster = 1; |
| 964 while (fClusters[glyphsInCluster] == cluster && |
| 965 glyphsInCluster < fGlyphCount) { |
| 966 ++glyphsInCluster; |
| 967 } |
| 968 SkASSERT(glyphsInCluster <= fGlyphCount); |
| 969 uint32_t textLength = 0; |
| 970 if (glyphsInCluster == fGlyphCount) { |
| 971 // consumes rest of glyphs and rest of text |
| 972 if (kInvalidCluster == fPreviousCluster) { // LTR text or single clu
ster |
| 973 textLength = fTextByteLength - cluster; |
| 974 } else { // RTL text; last cluster. |
| 975 SkASSERT(fPreviousCluster < fTextByteLength); |
| 976 if (fPreviousCluster <= cluster) { // bad input. |
| 977 return Cluster{nullptr, 0, 0, 0}; |
| 978 } |
| 979 textLength = fPreviousCluster - cluster; |
| 980 } |
| 981 fGlyphCount = 0; |
| 982 return Cluster{fUtf8Text + cluster, |
| 983 textLength, |
| 984 fGlyphIndex, |
| 985 glyphsInCluster}; |
| 986 } |
| 987 uint32_t nextCluster = fClusters[glyphsInCluster]; |
| 988 if (nextCluster >= fTextByteLength) { |
| 989 return Cluster{nullptr, 0, 0, 0}; // bad input. |
| 990 } |
| 991 if (nextCluster > cluster) { // LTR text |
| 992 if (kInvalidCluster != fPreviousCluster) { |
| 993 return Cluster{nullptr, 0, 0, 0}; // bad input. |
| 994 } |
| 995 textLength = nextCluster - cluster; |
| 996 } else { // RTL text |
| 997 SkASSERT(nextCluster < cluster); |
| 998 if (kInvalidCluster == fPreviousCluster) { // first cluster |
| 999 textLength = fTextByteLength - cluster; |
| 1000 } else { // later cluster |
| 1001 if (fPreviousCluster <= cluster) { |
| 1002 return Cluster{nullptr, 0, 0, 0}; // bad input. |
| 1003 } |
| 1004 textLength = fPreviousCluster - cluster; |
| 1005 } |
| 1006 fPreviousCluster = cluster; |
| 1007 } |
| 1008 uint32_t glyphIndex = fGlyphIndex; |
| 1009 fGlyphCount -= glyphsInCluster; |
| 1010 fGlyphIndex += glyphsInCluster; |
| 1011 fClusters += glyphsInCluster; |
| 1012 return Cluster{fUtf8Text + cluster, |
| 1013 textLength, |
| 1014 glyphIndex, |
| 1015 glyphsInCluster}; |
| 1016 } |
| 1017 |
| 1018 private: |
| 1019 static constexpr uint32_t kInvalidCluster = 0xFFFFFFFF; |
| 1020 const uint32_t* fClusters; |
| 1021 uint32_t fGlyphIndex = 0; |
| 1022 uint32_t fGlyphCount; |
| 1023 uint32_t fPreviousCluster = kInvalidCluster; |
| 1024 uint32_t fTextByteLength; |
| 1025 const char* fUtf8Text; |
| 1026 }; |
929 } // namespace | 1027 } // namespace |
930 | 1028 |
931 static void draw_transparent_text(SkPDFDevice* device, | 1029 static void draw_transparent_text(SkPDFDevice* device, |
932 const SkDraw& d, | 1030 const SkDraw& d, |
933 const void* text, size_t len, | 1031 const void* text, size_t len, |
934 SkScalar x, SkScalar y, | 1032 SkScalar x, SkScalar y, |
935 const SkPaint& srcPaint) { | 1033 const SkPaint& srcPaint) { |
936 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault(); | 1034 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault(); |
937 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(), device->getCanon())) { | 1035 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(), device->getCanon())) { |
938 SkDebugf("SkPDF: default typeface should be embeddable"); | 1036 SkDebugf("SkPDF: default typeface should be embeddable"); |
(...skipping 23 matching lines...) Expand all Loading... |
962 case SkPaint::kUTF16_TextEncoding: | 1060 case SkPaint::kUTF16_TextEncoding: |
963 case SkPaint::kUTF32_TextEncoding: | 1061 case SkPaint::kUTF32_TextEncoding: |
964 transparent.setTextEncoding(srcPaint.getTextEncoding()); | 1062 transparent.setTextEncoding(srcPaint.getTextEncoding()); |
965 device->drawText(d, text, len, x, y, transparent); | 1063 device->drawText(d, text, len, x, y, transparent); |
966 break; | 1064 break; |
967 default: | 1065 default: |
968 SkFAIL("unknown text encoding"); | 1066 SkFAIL("unknown text encoding"); |
969 } | 1067 } |
970 } | 1068 } |
971 | 1069 |
| 1070 static SkUnichar map_glyph(const SkAdvancedTypefaceMetrics& metrics, SkGlyphID g
lyph) { |
| 1071 return SkToInt(glyph) < metrics.fGlyphToUnicode.count() |
| 1072 ? metrics.fGlyphToUnicode[SkToInt(glyph)] |
| 1073 : -1; // represent unmapped value |
| 1074 } |
| 1075 |
| 1076 // TODO: move into SkPDFUtils.h |
| 1077 static void write_utf16be(SkDynamicMemoryWStream* wStream, SkUnichar utf32) { |
| 1078 SkGlyphID utf16[2] = {0, 0}; |
| 1079 size_t len = SkUTF16_FromUnichar(utf32, utf16); |
| 1080 SkASSERT(len == 1 || len == 2); |
| 1081 SkPDFUtils::WriteUInt16BE(wStream, utf16[0]); |
| 1082 if (len == 2) { |
| 1083 SkPDFUtils::WriteUInt16BE(wStream, utf16[1]); |
| 1084 } |
| 1085 } |
| 1086 |
| 1087 static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) { |
| 1088 wStream->writeText("/"); |
| 1089 char prefix = SkPDFResourceDict::GetResourceTypePrefix(SkPDFResourceDict::kF
ont_ResourceType); |
| 1090 wStream->write(&prefix, 1); |
| 1091 wStream->writeDecAsText(fontIndex); |
| 1092 wStream->writeText(" "); |
| 1093 SkPDFUtils::AppendScalar(textSize, wStream); |
| 1094 wStream->writeText(" Tf\n"); |
| 1095 } |
| 1096 |
972 void SkPDFDevice::internalDrawText( | 1097 void SkPDFDevice::internalDrawText( |
973 const SkDraw& d, const void* sourceText, size_t sourceByteCount, | 1098 const SkDraw& d, const void* sourceText, size_t sourceByteCount, |
974 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, | 1099 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, |
975 SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters, | 1100 SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters, |
976 uint32_t textByteLength, const char* utf8Text) { | 1101 uint32_t textByteLength, const char* utf8Text) { |
977 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); | 1102 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); |
978 if (srcPaint.getMaskFilter() != nullptr) { | 1103 if (srcPaint.getMaskFilter() != nullptr) { |
979 // Don't pretend we support drawing MaskFilters, it makes for artifacts | 1104 // Don't pretend we support drawing MaskFilters, it makes for artifacts |
980 // making text unreadable (e.g. same text twice when using CSS shadows). | 1105 // making text unreadable (e.g. same text twice when using CSS shadows). |
981 return; | 1106 return; |
982 } | 1107 } |
983 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); | 1108 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); |
984 if (srcPaint.isVerticalText()) { | 1109 if (srcPaint.isVerticalText()) { |
985 // Don't pretend we support drawing vertical text. It is not | 1110 // Don't pretend we support drawing vertical text. It is not |
986 // clear to me how to switch to "vertical writing" mode in PDF. | 1111 // clear to me how to switch to "vertical writing" mode in PDF. |
987 // Currently neither Chromium or Android set this flag. | 1112 // Currently neither Chromium or Android set this flag. |
988 // https://bug.skia.org/5665 | 1113 // https://bug.skia.org/5665 |
989 return; | 1114 return; |
990 } | 1115 } |
991 // TODO(halcanary): implement /ActualText with these values. | |
992 (void)clusters; | |
993 (void)textByteLength; | |
994 (void)utf8Text; | |
995 if (textByteLength > 0) { | |
996 SkASSERT(clusters); | |
997 SkASSERT(utf8Text); | |
998 SkASSERT(srcPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); | |
999 } else { | |
1000 SkASSERT(nullptr == clusters); | |
1001 SkASSERT(nullptr == utf8Text); | |
1002 } | |
1003 | |
1004 SkPaint paint = calculate_text_paint(srcPaint); | 1116 SkPaint paint = calculate_text_paint(srcPaint); |
1005 replace_srcmode_on_opaque_paint(&paint); | 1117 replace_srcmode_on_opaque_paint(&paint); |
1006 if (!paint.getTypeface()) { | 1118 if (!paint.getTypeface()) { |
1007 paint.setTypeface(SkTypeface::MakeDefault()); | 1119 paint.setTypeface(SkTypeface::MakeDefault()); |
1008 } | 1120 } |
1009 SkTypeface* typeface = paint.getTypeface(); | 1121 SkTypeface* typeface = paint.getTypeface(); |
1010 if (!typeface) { | 1122 if (!typeface) { |
1011 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); | 1123 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); |
1012 return; | 1124 return; |
1013 } | 1125 } |
1014 | 1126 |
1015 const SkAdvancedTypefaceMetrics* metrics = | 1127 const SkAdvancedTypefaceMetrics* metrics = |
1016 SkPDFFont::GetMetrics(typeface, fDocument->canon()); | 1128 SkPDFFont::GetMetrics(typeface, fDocument->canon()); |
1017 if (!metrics) { | 1129 if (!metrics) { |
1018 return; | 1130 return; |
1019 } | 1131 } |
1020 // TODO(halcanary): use metrics->fGlyphToUnicode to check Unicode mapping. | 1132 // TODO(halcanary): use metrics->fGlyphToUnicode to check Unicode mapping. |
1021 const SkGlyphID maxGlyphID = metrics->fLastGlyphID; | |
1022 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { | 1133 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { |
1023 SkPath path; // https://bug.skia.org/3866 | 1134 SkPath path; // https://bug.skia.org/3866 |
1024 paint.getTextPath(sourceText, sourceByteCount, | 1135 paint.getTextPath(sourceText, sourceByteCount, |
1025 offset.x(), offset.y(), &path); | 1136 offset.x(), offset.y(), &path); |
1026 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); | 1137 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); |
1027 // Draw text transparently to make it copyable/searchable/accessable. | 1138 // Draw text transparently to make it copyable/searchable/accessable. |
1028 draw_transparent_text(this, d, sourceText, sourceByteCount, | 1139 draw_transparent_text(this, d, sourceText, sourceByteCount, |
1029 offset.x(), offset.y(), paint); | 1140 offset.x(), offset.y(), paint); |
1030 return; | 1141 return; |
1031 } | 1142 } |
1032 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); | 1143 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); |
1033 if (glyphCount <= 0) { | 1144 if (glyphCount <= 0) { |
1034 return; | 1145 return; |
1035 } | 1146 } |
1036 SkAutoSTMalloc<128, SkGlyphID> glyphStorage; | 1147 SkAutoSTMalloc<128, SkGlyphID> glyphStorage; |
1037 const SkGlyphID* glyphs = nullptr; | 1148 const SkGlyphID* glyphs = nullptr; |
1038 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { | 1149 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) { |
1039 glyphs = (const SkGlyphID*)sourceText; | 1150 glyphs = (const SkGlyphID*)sourceText; |
1040 // validate input later. | 1151 // validate input later. |
1041 } else { | 1152 } else { |
1042 glyphStorage.reset(SkToSizeT(glyphCount)); | 1153 glyphStorage.reset(SkToSizeT(glyphCount)); |
1043 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphStorage.get()
); | 1154 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphStorage.get()
); |
1044 glyphs = glyphStorage.get(); | 1155 glyphs = glyphStorage.get(); |
1045 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 1156 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
1046 } | 1157 } |
1047 | 1158 |
| 1159 Clusterator clusterator(glyphCount); |
| 1160 if (textByteLength > 0) { |
| 1161 SkASSERT(clusters); |
| 1162 SkASSERT(utf8Text); |
| 1163 SkASSERT(srcPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); |
| 1164 clusterator = Clusterator(clusters, glyphCount, textByteLength, utf8Text
); |
| 1165 } else { |
| 1166 SkASSERT(nullptr == clusters); |
| 1167 SkASSERT(nullptr == utf8Text); |
| 1168 } |
| 1169 |
1048 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); | 1170 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); |
1049 paint.setHinting(SkPaint::kNo_Hinting); | 1171 paint.setHinting(SkPaint::kNo_Hinting); |
1050 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); | 1172 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); |
1051 | 1173 |
1052 SkPaint::Align alignment = paint.getTextAlign(); | 1174 SkPaint::Align alignment = paint.getTextAlign(); |
1053 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f : | 1175 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f : |
1054 SkPaint::kCenter_Align == alignment ? -0.5f : | 1176 SkPaint::kCenter_Align == alignment ? -0.5f : |
1055 /* SkPaint::kRight_Align */ -1.0f; | 1177 /* SkPaint::kRight_Align */ -1.0f; |
1056 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { | 1178 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { |
1057 SkScalar advance = 0; | 1179 SkScalar advance = 0; |
1058 for (int i = 0; i < glyphCount; ++i) { | 1180 for (int i = 0; i < glyphCount; ++i) { |
1059 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; | 1181 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; |
1060 } | 1182 } |
1061 offset.offset(alignmentFactor * advance, 0); | 1183 offset.offset(alignmentFactor * advance, 0); |
1062 } | 1184 } |
1063 ScopedContentEntry content(this, d, paint, true); | 1185 ScopedContentEntry content(this, d, paint, true); |
1064 if (!content.entry()) { | 1186 if (!content.entry()) { |
1065 return; | 1187 return; |
1066 } | 1188 } |
1067 SkDynamicMemoryWStream* out = &content.entry()->fContent; | 1189 SkDynamicMemoryWStream* out = &content.entry()->fContent; |
1068 SkScalar textSize = paint.getTextSize(); | 1190 SkScalar textSize = paint.getTextSize(); |
1069 | 1191 |
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"); | 1192 out->writeText("BT\n"); |
1079 SK_AT_SCOPE_EXIT(out->writeText("ET\n")); | 1193 SK_AT_SCOPE_EXIT(out->writeText("ET\n")); |
1080 | 1194 |
1081 SkPDFFont* font = this->updateFont( | 1195 const SkGlyphID maxGlyphID = metrics->fLastGlyphID; |
1082 typeface, textSize, glyphs[index], content.entry()); | 1196 bool multiByte = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics)); |
1083 SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met
. | |
1084 if (!font) { return; } | |
1085 | |
1086 GlyphPositioner glyphPositioner(out, | 1197 GlyphPositioner glyphPositioner(out, |
1087 paint.getTextSkewX(), | 1198 paint.getTextSkewX(), |
1088 font->multiByteGlyphs(), | 1199 multiByte, |
1089 defaultPositioning, | 1200 defaultPositioning, |
1090 offset); | 1201 offset); |
| 1202 SkPDFFont* font = nullptr; |
| 1203 while (Clusterator::Cluster c = clusterator.next()) { |
| 1204 int glyphIndex = c.fGlyphIndex; |
| 1205 int glyphLimit = glyphIndex + c.fGlyphCount; |
1091 | 1206 |
1092 while (index < glyphCount) { | 1207 bool actualText = false; |
1093 int stretch = font->countStretch(&glyphs[index], glyphCount - index, max
GlyphID); | 1208 SK_AT_SCOPE_EXIT2(if (actualText) { glyphPositioner.flush(); out->writeT
ext("EMC\n"); } ); |
1094 SkASSERT(index + stretch <= glyphCount); | 1209 if (c.fUtf8Text) { // real cluster |
1095 if (stretch < 1) { | 1210 // Check if `/ActualText` needed. |
1096 // The current pdf font cannot encode the next glyph. | 1211 const char* textPtr = c.fUtf8Text; |
1097 // Try to get a pdf font which can encode the next glyph. | 1212 // TODO(halcanary): validate utf8 input. |
1098 glyphPositioner.flush(); | 1213 SkUnichar unichar = SkUTF8_NextUnichar(&textPtr); |
1099 // first, validate the next glyph | 1214 const char* textEnd = c.fUtf8Text + c.fTextByteLength; |
1100 while (glyphs[index] > maxGlyphID) { | 1215 if (textPtr < textEnd || // more c
haracters left |
1101 ++index; // Skip this glyphID | 1216 glyphLimit > glyphIndex + 1 || // toUnic
ode wouldn't work |
1102 if (index == glyphCount) { | 1217 unichar != map_glyph(*metrics, glyphs[glyphIndex])) { // altern
ate map for single unichar |
1103 return; // all remainng glyphIDs were bad. | 1218 // actual text |
| 1219 // TODO: consider not hex-endoding string. |
| 1220 glyphPositioner.flush(); |
| 1221 out->writeText("/Span<</ActualText <"); |
| 1222 write_utf16be(out, 0xFEFF); // U+FEFF = BYTE ORDER MARK |
| 1223 // the BOM marks this text as utf16be, not latin. |
| 1224 write_utf16be(out, unichar); // first char |
| 1225 while (textPtr < textEnd) { |
| 1226 unichar = SkUTF8_NextUnichar(&textPtr); |
| 1227 write_utf16be(out, unichar); |
| 1228 } |
| 1229 out->writeText("> >> BDC\n"); // begin marked-content sequence |
| 1230 // with an associated property li
st. |
| 1231 actualText = true; |
| 1232 } |
| 1233 } |
| 1234 while (glyphs[glyphIndex] > maxGlyphID && glyphIndex < glyphLimit) { //
Invalid glyphID for this font. |
| 1235 ++glyphIndex; // Skip this glyphID |
| 1236 } |
| 1237 while (glyphIndex < glyphLimit) { |
| 1238 if (!font || // not yet specified font |
| 1239 !font->hasGlyph(glyphs[glyphIndex])) { // Need to switch font. |
| 1240 int fontIndex = this->getFontResourceIndex(typeface, glyphs[glyp
hIndex]); |
| 1241 SkASSERT(fontIndex >= 0); |
| 1242 if (fontIndex < 0) { |
| 1243 goto clusterLoopEnd; |
| 1244 } |
| 1245 glyphPositioner.flush(); |
| 1246 //static void update_font(SkWStream* wStream, int fontIndex, SkS
calar textSize) { |
| 1247 update_font(out, fontIndex, textSize); |
| 1248 font = fFontResources[fontIndex]; |
| 1249 SkASSERT(font); // All preconditions for SkPDFFont::GetFontReso
urce are met. |
| 1250 if (!font) { |
| 1251 goto clusterLoopEnd; |
1104 } | 1252 } |
1105 } | 1253 } |
1106 SkASSERT(index < glyphCount); | 1254 int stretch = font->countStretch(&glyphs[glyphIndex], glyphLimit - g
lyphIndex, maxGlyphID); |
1107 font = this->updateFont(typeface, textSize, glyphs[index], content.e
ntry()); | 1255 SkASSERT(glyphIndex + stretch <= glyphLimit); |
1108 SkASSERT(font); // preconditions for SkPDFFont::GetFontResource met
. | 1256 SkASSERT(stretch >= 1); // we just got the font for glyphs[glyphInd
ex], |
1109 if (!font) { return; } | 1257 if (stretch < 1) { // so we are guaranteed to get at least 1. |
1110 glyphPositioner.setWideChars(font->multiByteGlyphs()); | 1258 goto clusterLoopEnd; |
1111 // Get stretch for this new font. | 1259 } |
1112 stretch = font->countStretch(&glyphs[index], glyphCount - index, max
GlyphID); | 1260 while (stretch-- > 0) { |
1113 if (stretch < 1) { | 1261 SkGlyphID gid = glyphs[glyphIndex]; |
1114 SkDEBUGFAIL("PDF could not encode glyph."); | 1262 if (gid <= maxGlyphID) { |
1115 return; | 1263 font->noteGlyphUsage(gid); |
| 1264 SkGlyphID encodedGlyph = font->glyphToPDFFontEncoding(gid); |
| 1265 if (defaultPositioning) { |
| 1266 glyphPositioner.writeGlyph(SkPoint{0, 0}, 0, encodedGlyp
h); |
| 1267 } else { |
| 1268 SkScalar advance = glyphCache->getGlyphIDAdvance(gid).fA
dvanceX; |
| 1269 SkPoint xy = SkTextBlob::kFull_Positioning == positionin
g |
| 1270 ? SkPoint{pos[2 * glyphIndex], pos[2 * glyphI
ndex + 1]} |
| 1271 : SkPoint{pos[glyphIndex], 0}; |
| 1272 if (alignment != SkPaint::kLeft_Align) { |
| 1273 xy.offset(alignmentFactor * advance, 0); |
| 1274 } |
| 1275 glyphPositioner.writeGlyph(xy, advance, encodedGlyph); |
| 1276 } |
| 1277 } |
| 1278 ++glyphIndex; |
1116 } | 1279 } |
1117 } | 1280 } |
1118 while (stretch-- > 0) { | 1281 clusterLoopEnd: (void)0; |
1119 SkGlyphID gid = glyphs[index]; | |
1120 if (gid <= maxGlyphID) { | |
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 } | 1282 } |
1139 } | 1283 } |
1140 | 1284 |
1141 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, | 1285 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, |
1142 SkScalar x, SkScalar y, const SkPaint& paint) { | 1286 SkScalar x, SkScalar y, const SkPaint& paint) { |
1143 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni
ng, | 1287 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni
ng, |
1144 SkPoint{x, y}, paint, nullptr, 0, nullptr); | 1288 SkPoint{x, y}, paint, nullptr, 0, nullptr); |
1145 } | 1289 } |
1146 | 1290 |
1147 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, | 1291 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 | 1974 // Assumes that xobject has been canonicalized (so we can directly compare |
1831 // pointers). | 1975 // pointers). |
1832 int result = fXObjectResources.find(xObject); | 1976 int result = fXObjectResources.find(xObject); |
1833 if (result < 0) { | 1977 if (result < 0) { |
1834 result = fXObjectResources.count(); | 1978 result = fXObjectResources.count(); |
1835 fXObjectResources.push(SkRef(xObject)); | 1979 fXObjectResources.push(SkRef(xObject)); |
1836 } | 1980 } |
1837 return result; | 1981 return result; |
1838 } | 1982 } |
1839 | 1983 |
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 | 1984 |
1864 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { | 1985 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { |
1865 sk_sp<SkPDFFont> newFont( | 1986 sk_sp<SkPDFFont> newFont( |
1866 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID)); | 1987 SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID)); |
1867 if (!newFont) { | 1988 if (!newFont) { |
1868 return -1; | 1989 return -1; |
1869 } | 1990 } |
1870 int resourceIndex = fFontResources.find(newFont.get()); | 1991 int resourceIndex = fFontResources.find(newFont.get()); |
1871 if (resourceIndex < 0) { | 1992 if (resourceIndex < 0) { |
1872 fDocument->registerFont(newFont.get()); | 1993 fDocument->registerFont(newFont.get()); |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2081 } | 2202 } |
2082 | 2203 |
2083 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { | 2204 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { |
2084 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), | 2205 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), |
2085 image->makeNonTextureImage()); | 2206 image->makeNonTextureImage()); |
2086 } | 2207 } |
2087 | 2208 |
2088 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { | 2209 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { |
2089 return nullptr; | 2210 return nullptr; |
2090 } | 2211 } |
OLD | NEW |