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

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

Issue 2322403002: SkPDF: Implement /ActualText to make text extraction correct. (Closed)
Patch Set: SkPDFUtils::WriteUTF16beHex 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 | « no previous file | src/pdf/SkPDFMakeToUnicodeCmap.cpp » ('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 865 matching lines...) Expand 10 before | Expand all | Expand 10 after
915 private: 917 private:
916 SkDynamicMemoryWStream* fContent; 918 SkDynamicMemoryWStream* fContent;
917 SkPoint fCurrentMatrixOrigin; 919 SkPoint fCurrentMatrixOrigin;
918 SkScalar fXAdvance = 0.0f; 920 SkScalar fXAdvance = 0.0f;
919 SkScalar fTextSkewX; 921 SkScalar fTextSkewX;
920 bool fWideChars; 922 bool fWideChars;
921 bool fInText = false; 923 bool fInText = false;
922 bool fInitialized = false; 924 bool fInitialized = false;
923 const bool fDefaultPositioning; 925 const bool fDefaultPositioning;
924 }; 926 };
927
928 // Given the m-to-n glyph-to-character mapping data (as returned by
929 // harfbuzz), iterate over the clusters.
bungeman-skia 2016/09/13 22:08:05 nit: this is a doc comment (not an implementation
hal.canary 2016/09/14 01:36:37 Done.
930 class Clusterator {
931 public:
932 Clusterator(int glyphCount = 0)
bungeman-skia 2016/09/13 22:08:05 Should be marked explicit. Is there a good reason
hal.canary 2016/09/14 01:36:37 Done. I also want an "empty Clusterator" construc
933 : fClusters(nullptr)
934 , fGlyphCount(SkToU32(glyphCount))
bungeman-skia 2016/09/13 22:08:05 Seems strange to take an int for glyphCount and th
hal.canary 2016/09/14 01:36:37 Done.
935 , fTextByteLength(0)
936 , fUtf8Text(nullptr) {}
937 Clusterator(const uint32_t* clusters,
938 int glyphCount,
939 uint32_t textByteLength,
940 const char* utf8Text)
941 : fClusters(clusters)
942 , fGlyphCount(SkToU32(glyphCount))
943 , fTextByteLength(textByteLength)
944 , fUtf8Text(utf8Text) {
945 // This is a cheap heuristic for /ReversedChars which seems to
946 // work for clusters produced by HarfBuzz
947 fReversedChars =
948 fUtf8Text && fClusters && fGlyphCount && fClusters[0] != 0;
949 }
950 struct Cluster {
951 const char* fUtf8Text;
952 uint32_t fTextByteLength;
953 uint32_t fGlyphIndex;
954 uint32_t fGlyphCount;
955 explicit operator bool() const { return fGlyphCount != 0; }
956 };
957 bool reversedChars() const { return fReversedChars; }
958 Cluster next() {
959 if (!fUtf8Text || !fClusters) {
960 // These glyphs have no text. Treat as one "cluster".
961 uint32_t glyphCount = fGlyphCount;
962 fGlyphCount = 0;
963 return Cluster{nullptr, 0, 0, glyphCount};
964 }
965 if (fGlyphCount == 0 || fTextByteLength == 0) {
966 return Cluster{nullptr, 0, 0, 0}; // empty
967 }
968 uint32_t cluster = fClusters[0];
969 if (cluster >= fTextByteLength) {
970 return Cluster{nullptr, 0, 0, 0}; // bad input.
971 }
972 uint32_t glyphsInCluster = 1;
973 while (fClusters[glyphsInCluster] == cluster &&
974 glyphsInCluster < fGlyphCount) {
975 ++glyphsInCluster;
976 }
977 SkASSERT(glyphsInCluster <= fGlyphCount);
978 uint32_t textLength = 0;
979 if (glyphsInCluster == fGlyphCount) {
980 // consumes rest of glyphs and rest of text
981 if (kInvalidCluster == fPreviousCluster) { // LTR text or single clu ster
982 textLength = fTextByteLength - cluster;
983 } else { // RTL text; last cluster.
984 SkASSERT(fPreviousCluster < fTextByteLength);
985 if (fPreviousCluster <= cluster) { // bad input.
986 return Cluster{nullptr, 0, 0, 0};
987 }
988 textLength = fPreviousCluster - cluster;
989 }
990 fGlyphCount = 0;
991 return Cluster{fUtf8Text + cluster,
992 textLength,
993 fGlyphIndex,
994 glyphsInCluster};
995 }
996 uint32_t nextCluster = fClusters[glyphsInCluster];
997 if (nextCluster >= fTextByteLength) {
998 return Cluster{nullptr, 0, 0, 0}; // bad input.
999 }
1000 if (nextCluster > cluster) { // LTR text
1001 if (kInvalidCluster != fPreviousCluster) {
1002 return Cluster{nullptr, 0, 0, 0}; // bad input.
1003 }
1004 textLength = nextCluster - cluster;
1005 } else { // RTL text
1006 SkASSERT(nextCluster < cluster);
1007 if (kInvalidCluster == fPreviousCluster) { // first cluster
1008 textLength = fTextByteLength - cluster;
1009 } else { // later cluster
1010 if (fPreviousCluster <= cluster) {
1011 return Cluster{nullptr, 0, 0, 0}; // bad input.
1012 }
1013 textLength = fPreviousCluster - cluster;
1014 }
1015 fPreviousCluster = cluster;
1016 }
1017 uint32_t glyphIndex = fGlyphIndex;
1018 fGlyphCount -= glyphsInCluster;
1019 fGlyphIndex += glyphsInCluster;
1020 fClusters += glyphsInCluster;
1021 return Cluster{fUtf8Text + cluster,
1022 textLength,
1023 glyphIndex,
1024 glyphsInCluster};
1025 }
1026
1027 private:
1028 static constexpr uint32_t kInvalidCluster = 0xFFFFFFFF;
1029 const uint32_t* fClusters;
1030 uint32_t fGlyphIndex = 0;
1031 uint32_t fGlyphCount;
1032 uint32_t fPreviousCluster = kInvalidCluster;
1033 uint32_t fTextByteLength;
1034 const char* fUtf8Text;
1035 bool fReversedChars = false;
1036 };
1037
1038 struct TextStorage {
1039 SkAutoTMalloc<char> fUtf8textStorage;
1040 SkAutoTMalloc<uint32_t> fClusterStorage;
1041 SkAutoTMalloc<SkGlyphID> fGlyphStorage;
1042 };
925 } // namespace 1043 } // namespace
926 1044
1045 // given some unicode text (as passed to drawText(), convert to glyphs
1046 // (via primitive shaping), while preserving glyph-to-character
bungeman-skia 2016/09/13 22:08:05 nit: doc comment
hal.canary 2016/09/14 01:36:37 Done.
1047 // mapping information.
1048 static Clusterator make_clusterator(
1049 const void* sourceText,
1050 size_t sourceByteCount,
1051 const SkPaint& paint,
1052 TextStorage* storage,
1053 int* glyphCountOut) {
1054 SkASSERT(SkPaint::kGlyphID_TextEncoding != paint.getTextEncoding());
1055 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr);
1056 if (glyphCountOut) {
1057 *glyphCountOut = glyphCount;
1058 }
1059 if (!glyphCount) {
1060 return Clusterator();
1061 }
1062 storage->fGlyphStorage.reset(SkToSizeT(glyphCount));
1063 (void)paint.textToGlyphs(sourceText, sourceByteCount, storage->fGlyphStorage .get());
1064 storage->fClusterStorage.reset(SkToSizeT(glyphCount));
1065 uint32_t* clusters = storage->fClusterStorage.get();
1066 uint32_t utf8ByteCount = 0;
1067 const char* utf8Text = nullptr;
1068 switch (paint.getTextEncoding()) {
1069 case SkPaint::kUTF8_TextEncoding: {
1070 const char* txtPtr = (const char*)sourceText;
1071 for (int i = 0; i < glyphCount; ++i) {
1072 clusters[i] = SkToU32(txtPtr - (const char*)sourceText);
1073 txtPtr += SkUTF8_LeadByteToCount(*(const unsigned char*)txtPtr);
1074 SkASSERT(txtPtr <= (const char*)sourceText + sourceByteCount);
1075 }
1076 utf8ByteCount = SkToU32(sourceByteCount);
1077 utf8Text = (const char*)sourceText;
1078 break;
1079 }
1080 case SkPaint::kUTF16_TextEncoding: {
1081 const uint16_t* utf16ptr = (const uint16_t*)sourceText;
1082 int utf16count = SkToInt(sourceByteCount / sizeof(uint16_t));
1083 utf8ByteCount = SkToU32(SkUTF16_ToUTF8(utf16ptr, utf16count));
1084 storage->fUtf8textStorage.reset(utf8ByteCount);
1085 char* txtPtr = storage->fUtf8textStorage.get();
1086 utf8Text = txtPtr;
1087 int clusterIndex = 0;
1088 while (utf16ptr < (const uint16_t*)sourceText + sourceByteCount) {
1089 clusters[clusterIndex++] = SkToU32(txtPtr - utf8Text);
1090 SkUnichar uni = SkUTF16_NextUnichar(&utf16ptr);
1091 txtPtr += SkUTF8_FromUnichar(uni, txtPtr);
1092 }
1093 SkASSERT(clusterIndex == glyphCount);
1094 SkASSERT(txtPtr == storage->fUtf8textStorage.get() + utf8ByteCount);
1095 SkASSERT(utf16ptr == (const uint16_t*)sourceText + sourceByteCount);
1096 break;
1097 }
1098 case SkPaint::kUTF32_TextEncoding: {
1099 const SkUnichar* utf32 = (const SkUnichar*)sourceText;
1100 for (size_t i = 0; i < sourceByteCount / sizeof(SkUnichar); ++i) {
1101 utf8ByteCount += SkToU32(SkUTF8_FromUnichar(utf32[i]));
1102 }
1103 storage->fUtf8textStorage.reset(SkToSizeT(utf8ByteCount));
1104 char* txtPtr = storage->fUtf8textStorage.get();
1105 utf8Text = txtPtr;
1106 for (size_t i = 0; i < sourceByteCount / sizeof(SkUnichar); ++i) {
1107 clusters[i] = SkToU32(txtPtr - utf8Text);
1108 txtPtr += SkUTF8_FromUnichar(utf32[i], txtPtr);
1109 }
1110 break;
1111 }
1112 default:
1113 SkDEBUGFAIL("");
1114 break;
1115 }
1116 return Clusterator(clusters, glyphCount, utf8ByteCount, utf8Text);
1117 }
1118
927 static void draw_transparent_text(SkPDFDevice* device, 1119 static void draw_transparent_text(SkPDFDevice* device,
928 const SkDraw& d, 1120 const SkDraw& d,
929 const void* text, size_t len, 1121 const void* text, size_t len,
930 SkScalar x, SkScalar y, 1122 SkScalar x, SkScalar y,
931 const SkPaint& srcPaint) { 1123 const SkPaint& srcPaint) {
932 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault(); 1124 sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault();
933 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(), device->getCanon())) { 1125 if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(), device->getCanon())) {
934 SkDebugf("SkPDF: default typeface should be embeddable"); 1126 SkDebugf("SkPDF: default typeface should be embeddable");
935 return; // Avoid infinite loop in release. 1127 return; // Avoid infinite loop in release.
936 } 1128 }
(...skipping 21 matching lines...) Expand all
958 case SkPaint::kUTF16_TextEncoding: 1150 case SkPaint::kUTF16_TextEncoding:
959 case SkPaint::kUTF32_TextEncoding: 1151 case SkPaint::kUTF32_TextEncoding:
960 transparent.setTextEncoding(srcPaint.getTextEncoding()); 1152 transparent.setTextEncoding(srcPaint.getTextEncoding());
961 device->drawText(d, text, len, x, y, transparent); 1153 device->drawText(d, text, len, x, y, transparent);
962 break; 1154 break;
963 default: 1155 default:
964 SkFAIL("unknown text encoding"); 1156 SkFAIL("unknown text encoding");
965 } 1157 }
966 } 1158 }
967 1159
1160 static SkUnichar map_glyph(const SkTDArray<SkUnichar>& glyphToUnicode, SkGlyphID glyph) {
1161 return SkToInt(glyph) < glyphToUnicode.count() ? glyphToUnicode[SkToInt(glyp h)] : -1;
1162 }
1163
968 static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) { 1164 static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) {
969 wStream->writeText("/"); 1165 wStream->writeText("/");
970 char prefix = SkPDFResourceDict::GetResourceTypePrefix(SkPDFResourceDict::kF ont_ResourceType); 1166 char prefix = SkPDFResourceDict::GetResourceTypePrefix(SkPDFResourceDict::kF ont_ResourceType);
971 wStream->write(&prefix, 1); 1167 wStream->write(&prefix, 1);
972 wStream->writeDecAsText(fontIndex); 1168 wStream->writeDecAsText(fontIndex);
973 wStream->writeText(" "); 1169 wStream->writeText(" ");
974 SkPDFUtils::AppendScalar(textSize, wStream); 1170 SkPDFUtils::AppendScalar(textSize, wStream);
975 wStream->writeText(" Tf\n"); 1171 wStream->writeText(" Tf\n");
976 } 1172 }
977 1173
978 void SkPDFDevice::internalDrawText( 1174 void SkPDFDevice::internalDrawText(
979 const SkDraw& d, const void* sourceText, size_t sourceByteCount, 1175 const SkDraw& d, const void* sourceText, size_t sourceByteCount,
980 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, 1176 const SkScalar pos[], SkTextBlob::GlyphPositioning positioning,
981 SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters, 1177 SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters,
982 uint32_t textByteLength, const char* utf8Text) { 1178 uint32_t textByteLength, const char* utf8Text) {
983 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false); 1179 NOT_IMPLEMENTED(srcPaint.getMaskFilter() != nullptr, false);
984 if (srcPaint.getMaskFilter() != nullptr) { 1180 if (srcPaint.getMaskFilter() != nullptr) {
985 // Don't pretend we support drawing MaskFilters, it makes for artifacts 1181 // Don't pretend we support drawing MaskFilters, it makes for artifacts
986 // making text unreadable (e.g. same text twice when using CSS shadows). 1182 // making text unreadable (e.g. same text twice when using CSS shadows).
987 return; 1183 return;
988 } 1184 }
989 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false); 1185 NOT_IMPLEMENTED(srcPaint.isVerticalText(), false);
990 if (srcPaint.isVerticalText()) { 1186 if (srcPaint.isVerticalText()) {
991 // Don't pretend we support drawing vertical text. It is not 1187 // Don't pretend we support drawing vertical text. It is not
992 // clear to me how to switch to "vertical writing" mode in PDF. 1188 // clear to me how to switch to "vertical writing" mode in PDF.
993 // Currently neither Chromium or Android set this flag. 1189 // Currently neither Chromium or Android set this flag.
994 // https://bug.skia.org/5665 1190 // https://bug.skia.org/5665
995 return; 1191 return;
996 } 1192 }
997 // TODO(halcanary): implement /ActualText with these values. 1193 if (0 == sourceByteCount || !sourceText) {
998 (void)clusters; 1194 return;
999 (void)textByteLength;
1000 (void)utf8Text;
1001 if (textByteLength > 0) {
1002 SkASSERT(clusters);
1003 SkASSERT(utf8Text);
1004 SkASSERT(srcPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
1005 } else {
1006 SkASSERT(nullptr == clusters);
1007 SkASSERT(nullptr == utf8Text);
1008 } 1195 }
1009
1010 SkPaint paint = calculate_text_paint(srcPaint); 1196 SkPaint paint = calculate_text_paint(srcPaint);
1011 replace_srcmode_on_opaque_paint(&paint); 1197 replace_srcmode_on_opaque_paint(&paint);
1012 if (!paint.getTypeface()) { 1198 if (!paint.getTypeface()) {
1013 paint.setTypeface(SkTypeface::MakeDefault()); 1199 paint.setTypeface(SkTypeface::MakeDefault());
1014 } 1200 }
1015 SkTypeface* typeface = paint.getTypeface(); 1201 SkTypeface* typeface = paint.getTypeface();
1016 if (!typeface) { 1202 if (!typeface) {
1017 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n"); 1203 SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n");
1018 return; 1204 return;
1019 } 1205 }
1020 1206
1021 const SkAdvancedTypefaceMetrics* metrics = 1207 const SkAdvancedTypefaceMetrics* metrics =
1022 SkPDFFont::GetMetrics(typeface, fDocument->canon()); 1208 SkPDFFont::GetMetrics(typeface, fDocument->canon());
1023 if (!metrics) { 1209 if (!metrics) {
1024 return; 1210 return;
1025 } 1211 }
1026 // TODO(halcanary): use metrics->fGlyphToUnicode to check Unicode mapping. 1212 // TODO(halcanary): use metrics->fGlyphToUnicode to check Unicode mapping.
1027 const SkGlyphID maxGlyphID = metrics->fLastGlyphID;
1028 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) { 1213 if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) {
1029 SkPath path; // https://bug.skia.org/3866 1214 SkPath path; // https://bug.skia.org/3866
1030 paint.getTextPath(sourceText, sourceByteCount, 1215 paint.getTextPath(sourceText, sourceByteCount,
1031 offset.x(), offset.y(), &path); 1216 offset.x(), offset.y(), &path);
1032 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); 1217 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true);
1033 // Draw text transparently to make it copyable/searchable/accessable. 1218 // Draw text transparently to make it copyable/searchable/accessable.
1034 draw_transparent_text(this, d, sourceText, sourceByteCount, 1219 draw_transparent_text(this, d, sourceText, sourceByteCount,
1035 offset.x(), offset.y(), paint); 1220 offset.x(), offset.y(), paint);
1036 return; 1221 return;
1037 } 1222 }
1038 int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr); 1223
1039 if (glyphCount <= 0) { 1224 // These three heap buffers are only used in the case where no glyphs
1225 // are passed to drawText() (most clients pass glyphs or a textblob).
1226 TextStorage storage;
1227 int glyphCount = 0;
1228 const SkGlyphID* glyphs = nullptr;
1229 Clusterator clusterator;
1230 if (textByteLength > 0) {
1231 glyphCount = SkToInt(sourceByteCount / sizeof(SkGlyphID));
1232 glyphs = (const SkGlyphID*)sourceText;
1233 clusterator = Clusterator(clusters, glyphCount, textByteLength, utf8Text );
1234 SkASSERT(clusters);
1235 SkASSERT(utf8Text);
1236 SkASSERT(srcPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
1237 SkASSERT(glyphCount == paint.textToGlyphs(sourceText, sourceByteCount, n ullptr));
1238 } else if (SkPaint::kGlyphID_TextEncoding == srcPaint.getTextEncoding()) {
1239 glyphCount = SkToInt(sourceByteCount / sizeof(SkGlyphID));
1240 glyphs = (const SkGlyphID*)sourceText;
1241 clusterator = Clusterator(glyphCount);
1242 SkASSERT(glyphCount == paint.textToGlyphs(sourceText, sourceByteCount, n ullptr));
1243 SkASSERT(nullptr == clusters);
1244 SkASSERT(nullptr == utf8Text);
1245 } else {
1246 SkASSERT(nullptr == clusters);
1247 SkASSERT(nullptr == utf8Text);
1248 clusterator = make_clusterator(sourceText, sourceByteCount, srcPaint,
1249 &storage, &glyphCount);
1250 glyphs = storage.fGlyphStorage;
1251 }
1252 if (0 == glyphCount) {
1040 return; 1253 return;
1041 } 1254 }
1042 SkAutoSTMalloc<128, SkGlyphID> glyphStorage;
1043 const SkGlyphID* glyphs = nullptr;
1044 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
1045 glyphs = (const SkGlyphID*)sourceText;
1046 // validate input later.
1047 } else {
1048 glyphStorage.reset(SkToSizeT(glyphCount));
1049 (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphStorage.get() );
1050 glyphs = glyphStorage.get();
1051 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
1052 }
1053
1054 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning); 1255 bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning);
1055 paint.setHinting(SkPaint::kNo_Hinting); 1256 paint.setHinting(SkPaint::kNo_Hinting);
1056 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr); 1257 SkAutoGlyphCache glyphCache(paint, nullptr, nullptr);
1057 1258
1058 SkPaint::Align alignment = paint.getTextAlign(); 1259 SkPaint::Align alignment = paint.getTextAlign();
1059 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f : 1260 float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f :
1060 SkPaint::kCenter_Align == alignment ? -0.5f : 1261 SkPaint::kCenter_Align == alignment ? -0.5f :
1061 /* SkPaint::kRight_Align */ -1.0f; 1262 /* SkPaint::kRight_Align */ -1.0f;
1062 if (defaultPositioning && alignment != SkPaint::kLeft_Align) { 1263 if (defaultPositioning && alignment != SkPaint::kLeft_Align) {
1063 SkScalar advance = 0; 1264 SkScalar advance = 0;
1064 for (int i = 0; i < glyphCount; ++i) { 1265 for (int i = 0; i < glyphCount; ++i) {
1065 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX; 1266 advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX;
1066 } 1267 }
1067 offset.offset(alignmentFactor * advance, 0); 1268 offset.offset(alignmentFactor * advance, 0);
1068 } 1269 }
1069 ScopedContentEntry content(this, d, paint, true); 1270 ScopedContentEntry content(this, d, paint, true);
1070 if (!content.entry()) { 1271 if (!content.entry()) {
1071 return; 1272 return;
1072 } 1273 }
1073 SkDynamicMemoryWStream* out = &content.entry()->fContent; 1274 SkDynamicMemoryWStream* out = &content.entry()->fContent;
1074 SkScalar textSize = paint.getTextSize(); 1275 SkScalar textSize = paint.getTextSize();
1276 const SkTDArray<SkUnichar>& glyphToUnicode = metrics->fGlyphToUnicode;
1075 1277
1076 out->writeText("BT\n"); 1278 out->writeText("BT\n");
1077 SK_AT_SCOPE_EXIT(out->writeText("ET\n")); 1279 SK_AT_SCOPE_EXIT(out->writeText("ET\n"));
1078 1280
1281 const SkGlyphID maxGlyphID = metrics->fLastGlyphID;
1079 bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics)) ; 1282 bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics)) ;
1283 if (clusterator.reversedChars()) {
1284 out->writeText("/ReversedChars BMC\n");
1285 }
1286 SK_AT_SCOPE_EXIT(if (clusterator.reversedChars()) { out->writeText("EMC\n"); } );
1080 GlyphPositioner glyphPositioner(out, 1287 GlyphPositioner glyphPositioner(out,
1081 paint.getTextSkewX(), 1288 paint.getTextSkewX(),
1082 multiByteGlyphs, 1289 multiByteGlyphs,
1083 defaultPositioning, 1290 defaultPositioning,
1084 offset); 1291 offset);
1085 SkPDFFont* font = nullptr; 1292 SkPDFFont* font = nullptr;
1086 for (int index = 0; index < glyphCount; ++index) { 1293
1087 SkGlyphID gid = glyphs[index]; 1294 while (Clusterator::Cluster c = clusterator.next()) {
1088 if (gid > maxGlyphID) { 1295 int index = c.fGlyphIndex;
1089 continue; // Skip this invalid glyphID. 1296 int glyphLimit = index + c.fGlyphCount;
1090 } 1297
1091 if (!font || !font->hasGlyph(gid)) { 1298 bool actualText = false;
1092 // Either this is the first loop iteration or the current 1299 SK_AT_SCOPE_EXIT(if (actualText) { glyphPositioner.flush(); out->writeTe xt("EMC\n"); } );
bungeman-skia 2016/09/13 22:08:05 I really wish there were a better way to structure
hal.canary 2016/09/14 01:36:37 Acknowledged.
1093 // PDFFont cannot encode this glyph. 1300 if (c.fUtf8Text) { // real cluster
1094 glyphPositioner.flush(); 1301 // Check if `/ActualText` needed.
1095 // Try to get a font which can encode the glyph. 1302 const char* textPtr = c.fUtf8Text;
1096 int fontIndex = this->getFontResourceIndex(typeface, gid); 1303 // TODO(halcanary): validate utf8 input.
1097 SkASSERT(fontIndex >= 0); 1304 SkUnichar unichar = SkUTF8_NextUnichar(&textPtr);
1098 if (fontIndex < 0) { return; } 1305 const char* textEnd = c.fUtf8Text + c.fTextByteLength;
1099 update_font(out, fontIndex, textSize); 1306 if (textPtr < textEnd || // more characters left
1100 font = fFontResources[fontIndex]; 1307 glyphLimit > index + 1 || // toUni code wouldn't work
1101 SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met. 1308 unichar != map_glyph(glyphToUnicode, glyphs[index])) { // test single Unichar map
bungeman-skia 2016/09/13 22:08:05 The '{' being at the end of this line makes it dif
hal.canary 2016/09/14 01:36:37 Done.
1102 if (!font) { return; } 1309 glyphPositioner.flush();
1103 SkASSERT(font->multiByteGlyphs() == multiByteGlyphs); 1310 out->writeText("/Span<</ActualText <");
1104 } 1311 SkPDFUtils::WriteUTF16beHex(out, 0xFEFF); // U+FEFF = BYTE ORDE R MARK
1105 font->noteGlyphUsage(gid); 1312 // the BOM marks this text as UTF-16BE, not PDFDocEncoding.
1106 SkScalar advance{0.0f}; 1313 SkPDFUtils::WriteUTF16beHex(out, unichar); // first char
1107 SkPoint xy{0.0f, 0.0f}; 1314 while (textPtr < textEnd) {
1108 if (!defaultPositioning) { 1315 unichar = SkUTF8_NextUnichar(&textPtr);
1109 advance = glyphCache->getGlyphIDAdvance(gid).fAdvanceX; 1316 SkPDFUtils::WriteUTF16beHex(out, unichar);
1110 xy = SkTextBlob::kFull_Positioning == positioning 1317 }
1111 ? SkPoint{pos[2 * index], pos[2 * index + 1]} 1318 out->writeText("> >> BDC\n"); // begin marked-content sequence
1112 : SkPoint{pos[index], 0}; 1319 // with an associated property li st.
1113 if (alignment != SkPaint::kLeft_Align) { 1320 actualText = true;
1114 xy.offset(alignmentFactor * advance, 0);
1115 } 1321 }
1116 } 1322 }
1117 SkGlyphID encodedGlyph = 1323 for (; index < glyphLimit; ++index) {
1118 multiByteGlyphs ? gid : font->glyphToPDFFontEncoding(gid); 1324 SkGlyphID gid = glyphs[index];
1119 glyphPositioner.writeGlyph(xy, advance, encodedGlyph); 1325 if (gid > maxGlyphID) {
1326 continue;
1327 }
1328 if (!font || !font->hasGlyph(gid)) {
1329 // Not yet specified font or need to switch font.
1330 int fontIndex = this->getFontResourceIndex(typeface, gid);
1331 // All preconditions for SkPDFFont::GetFontResource are met.
1332 SkASSERT(fontIndex >= 0);
1333 if (fontIndex < 0) {
1334 return;
1335 }
1336 glyphPositioner.flush();
1337 update_font(out, fontIndex, textSize);
1338 font = fFontResources[fontIndex];
1339 SkASSERT(font); // All preconditions for SkPDFFont::GetFontReso urce are met.
1340 if (!font) {
1341 return;
1342 }
1343 SkASSERT(font->multiByteGlyphs() == multiByteGlyphs);
1344 }
1345 SkPoint xy{0, 0};
1346 SkScalar advance{0};
1347 if (!defaultPositioning) {
1348 advance = glyphCache->getGlyphIDAdvance(gid).fAdvanceX;
1349 xy = SkTextBlob::kFull_Positioning == positioning
1350 ? SkPoint{pos[2 * index], pos[2 * index + 1]}
1351 : SkPoint{pos[index], 0};
1352 if (alignment != SkPaint::kLeft_Align) {
1353 xy.offset(alignmentFactor * advance, 0);
1354 }
1355 }
1356 font->noteGlyphUsage(gid);
1357 SkGlyphID encodedGlyph = multiByteGlyphs ? gid : font->glyphToPDFFon tEncoding(gid);
1358 glyphPositioner.writeGlyph(xy, advance, encodedGlyph);
1359 }
1120 } 1360 }
1121 } 1361 }
1122 1362
1123 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, 1363 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
1124 SkScalar x, SkScalar y, const SkPaint& paint) { 1364 SkScalar x, SkScalar y, const SkPaint& paint) {
1125 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng, 1365 this->internalDrawText(d, text, len, nullptr, SkTextBlob::kDefault_Positioni ng,
1126 SkPoint{x, y}, paint, nullptr, 0, nullptr); 1366 SkPoint{x, y}, paint, nullptr, 0, nullptr);
1127 } 1367 }
1128 1368
1129 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, 1369 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
(...skipping 909 matching lines...) Expand 10 before | Expand all | Expand 10 after
2039 } 2279 }
2040 2280
2041 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { 2281 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) {
2042 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()), 2282 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image-> height()),
2043 image->makeNonTextureImage()); 2283 image->makeNonTextureImage());
2044 } 2284 }
2045 2285
2046 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { 2286 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() {
2047 return nullptr; 2287 return nullptr;
2048 } 2288 }
OLDNEW
« no previous file with comments | « no previous file | src/pdf/SkPDFMakeToUnicodeCmap.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698