Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(129)

Side by Side Diff: src/pdf/SkPDFDevice.cpp

Issue 2330503002: work in progress (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pdf/SkPDFDevice.h ('k') | src/pdf/SkPDFFont.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFDevice.h ('k') | src/pdf/SkPDFFont.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698