diff options
author | Mike Reed <reed@google.com> | 2017-07-17 21:12:19 +0000 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-07-17 21:12:30 +0000 |
commit | 63b6f8b93209e593f60b235577f5b3d660396d5f (patch) | |
tree | 4864da686054d19002996f539b699e499018533a /src/pdf | |
parent | 0983268dd52150fb968fb10bed2e8541095f12a1 (diff) |
Revert "SkPDF: Non-outline glyphs as images"
This reverts commit 3cf6b79e50f148cae7ed8c6ec0cd79f1ede71c95.
Reason for revert: breaking build
../../../../../work/skia/src/pdf/SkPDFDevice.cpp: In member function 'void SkPDFDevice::internalDrawText(const void*, size_t, const SkScalar*, SkTextBlob::GlyphPositioning, SkPoint, const SkPaint&, const uint32_t*, uint32_t, const char*)':
../../../../../work/skia/src/pdf/SkPDFDevice.cpp:1578:31: error: missing initializer for member 'SkPoint::fX' [-Werror=missing-field-initializers]
SkPoint xy = {};
^
Original change's description:
> SkPDF: Non-outline glyphs as images
>
> - Cache images in PDF Canon for de-duping
> - For now, rasterize at text scale. in the future, look at CTM and
> fRasterScale.
> - add a test that works on MacOS
>
> BUG=chromium:705480
> BUG=skia:3489
> Change-Id: I4fbc42f218e5b81ea15ea6cdccc61c91e532f6d0
> Reviewed-on: https://skia-review.googlesource.com/24080
> Commit-Queue: Hal Canary <halcanary@google.com>
> Reviewed-by: Ben Wagner <bungeman@google.com>
TBR=halcanary@google.com,bungeman@google.com
Change-Id: I3d8800fcb33817c6065da0860a534eb14350d132
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: chromium:705480, skia:3489
Reviewed-on: https://skia-review.googlesource.com/24160
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
Diffstat (limited to 'src/pdf')
-rw-r--r-- | src/pdf/SkPDFCanon.h | 25 | ||||
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 294 |
2 files changed, 98 insertions, 221 deletions
diff --git a/src/pdf/SkPDFCanon.h b/src/pdf/SkPDFCanon.h index 8edd06e391..03671bf921 100644 --- a/src/pdf/SkPDFCanon.h +++ b/src/pdf/SkPDFCanon.h @@ -7,14 +7,13 @@ #ifndef SkPDFCanon_DEFINED #define SkPDFCanon_DEFINED -#include "SkBitmapKey.h" -#include "SkPDFGradientShader.h" #include "SkPDFGraphicState.h" #include "SkPDFShader.h" +#include "SkPDFGradientShader.h" #include "SkPixelSerializer.h" #include "SkTDArray.h" #include "SkTHash.h" -#include "SkTypeface.h" +#include "SkBitmapKey.h" class SkPDFFont; struct SkAdvancedTypefaceMetrics; @@ -47,25 +46,5 @@ public: sk_sp<SkPDFStream> fInvertFunction; sk_sp<SkPDFDict> fNoSmaskGraphicState; sk_sp<SkPDFArray> fRangeObject; - - SK_BEGIN_REQUIRE_DENSE - struct BitmapGlyphKey { - SkFontID fFontID; // uint32_t - SkScalar fTextSize; // float32 - SkScalar fTextScaleX; // float32 - SkScalar fTextSkewX; // float32 - SkGlyphID fGlyphID; // uint16_t - uint16_t fPadding; - }; - SK_END_REQUIRE_DENSE - struct BitmapGlyph { - sk_sp<SkImage> fImage; - SkIPoint fOffset; - }; - SkTHashMap<BitmapGlyphKey, BitmapGlyph> fBitmapGlyphImages; }; - -inline bool operator==(const SkPDFCanon::BitmapGlyphKey& u, const SkPDFCanon::BitmapGlyphKey& v) { - return memcmp(&u, &u, sizeof(SkPDFCanon::BitmapGlyphKey)) == 0; -} #endif // SkPDFCanon_DEFINED diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index 7a2d51c848..bbc09f7ed6 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -1320,12 +1320,6 @@ static SkPath draw_text_as_path(const void* sourceText, size_t sourceByteCount, return path; } -static bool has_outline_glyph(SkGlyphID gid, SkGlyphCache* cache) { - const SkGlyph& glyph = cache->getGlyphIDMetrics(gid); - const SkPath* path = cache->findPath(glyph); - return (path && !path->isEmpty()) || (glyph.fWidth == 0 && glyph.fHeight == 0); -} - static SkRect get_glyph_bounds_device_space(SkGlyphID gid, SkGlyphCache* cache, SkScalar xScale, SkScalar yScale, SkPoint xy, const SkMatrix& ctm) { @@ -1344,46 +1338,6 @@ static bool contains(const SkRect& r, SkPoint p) { r.top() <= p.y() && p.y() <= r.bottom(); } -static sk_sp<SkImage> image_from_mask(const SkMask& mask) { - if (!mask.fImage) { - return nullptr; - } - SkIRect bounds = mask.fBounds; - SkBitmap bm; - switch (mask.fFormat) { - case SkMask::kBW_Format: - bm.allocPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height())); - for (int y = 0; y < bm.height(); ++y) { - for (int x8 = 0; x8 < bm.width(); x8 += 8) { - uint8_t v = *mask.getAddr1(x8 + bounds.x(), y + bounds.y()); - int e = SkTMin(x8 + 8, bm.width()); - for (int x = x8; x < e; ++x) { - *bm.getAddr8(x, y) = (v >> (x & 0x7)) & 0x1 ? 0xFF : 0x00; - } - } - } - bm.setImmutable(); - return SkImage::MakeFromBitmap(bm); - case SkMask::kA8_Format: - bm.installPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height()), - mask.fImage, mask.fRowBytes); - return SkMakeImageFromRasterBitmap(bm, kAlways_SkCopyPixelsMode); - case SkMask::kARGB32_Format: - bm.installPixels(SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()), - mask.fImage, mask.fRowBytes); - return SkMakeImageFromRasterBitmap(bm, kAlways_SkCopyPixelsMode); - case SkMask::k3D_Format: - SkASSERT(false); - return nullptr; - case SkMask::kLCD16_Format: - SkASSERT(false); - return nullptr; - default: - SkASSERT(false); - return nullptr; - } -} - void SkPDFDevice::internalDrawText( const void* sourceText, size_t sourceByteCount, const SkScalar pos[], SkTextBlob::GlyphPositioning positioning, @@ -1485,169 +1439,113 @@ void SkPDFDevice::internalDrawText( offset.offset(alignmentFactor * advance, 0); } SkRect clipStackBounds = this->cs().bounds(size(*this)); - struct PositionedGlyph { - SkPoint fPos; - SkGlyphID fGlyph; - }; - SkTArray<PositionedGlyph> fMissingGlyphs; - { - ScopedContentEntry content(this, paint, true); - if (!content.entry()) { - return; + ScopedContentEntry content(this, paint, true); + if (!content.entry()) { + return; + } + SkDynamicMemoryWStream* out = content.stream(); + const SkTDArray<SkUnichar>& glyphToUnicode = metrics->fGlyphToUnicode; + + out->writeText("BT\n"); + SK_AT_SCOPE_EXIT(out->writeText("ET\n")); + + const SkGlyphID maxGlyphID = SkToU16(typeface->countGlyphs() - 1); + + bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics)); + if (clusterator.reversedChars()) { + out->writeText("/ReversedChars BMC\n"); + } + SK_AT_SCOPE_EXIT(if (clusterator.reversedChars()) { out->writeText("EMC\n"); } ); + GlyphPositioner glyphPositioner(out, + paint.getTextSkewX(), + multiByteGlyphs, + defaultPositioning, + offset); + SkPDFFont* font = nullptr; + + while (Clusterator::Cluster c = clusterator.next()) { + int index = c.fGlyphIndex; + int glyphLimit = index + c.fGlyphCount; + + bool actualText = false; + SK_AT_SCOPE_EXIT(if (actualText) { glyphPositioner.flush(); out->writeText("EMC\n"); } ); + if (c.fUtf8Text) { // real cluster + // Check if `/ActualText` needed. + const char* textPtr = c.fUtf8Text; + const char* textEnd = c.fUtf8Text + c.fTextByteLength; + SkUnichar unichar = SkUTF8_NextUnicharWithError(&textPtr, textEnd); + if (unichar < 0) { + return; + } + if (textPtr < textEnd || // more characters left + glyphLimit > index + 1 || // toUnicode wouldn't work + unichar != map_glyph(glyphToUnicode, glyphs[index])) // test single Unichar map + { + glyphPositioner.flush(); + out->writeText("/Span<</ActualText <"); + SkPDFUtils::WriteUTF16beHex(out, 0xFEFF); // U+FEFF = BYTE ORDER MARK + // the BOM marks this text as UTF-16BE, not PDFDocEncoding. + SkPDFUtils::WriteUTF16beHex(out, unichar); // first char + while (textPtr < textEnd) { + unichar = SkUTF8_NextUnicharWithError(&textPtr, textEnd); + if (unichar < 0) { + break; + } + SkPDFUtils::WriteUTF16beHex(out, unichar); + } + out->writeText("> >> BDC\n"); // begin marked-content sequence + // with an associated property list. + actualText = true; + } } - SkDynamicMemoryWStream* out = content.stream(); - const SkTDArray<SkUnichar>& glyphToUnicode = metrics->fGlyphToUnicode; - - out->writeText("BT\n"); - SK_AT_SCOPE_EXIT(out->writeText("ET\n")); - - const SkGlyphID maxGlyphID = SkToU16(typeface->countGlyphs() - 1); - - bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics)); - if (clusterator.reversedChars()) { - out->writeText("/ReversedChars BMC\n"); - } - SK_AT_SCOPE_EXIT(if (clusterator.reversedChars()) { out->writeText("EMC\n"); } ); - GlyphPositioner glyphPositioner(out, - paint.getTextSkewX(), - multiByteGlyphs, - defaultPositioning, - offset); - SkPDFFont* font = nullptr; - - while (Clusterator::Cluster c = clusterator.next()) { - int index = c.fGlyphIndex; - int glyphLimit = index + c.fGlyphCount; - - bool actualText = false; - SK_AT_SCOPE_EXIT(if (actualText) { - glyphPositioner.flush(); - out->writeText("EMC\n"); - }); - if (c.fUtf8Text) { // real cluster - // Check if `/ActualText` needed. - const char* textPtr = c.fUtf8Text; - const char* textEnd = c.fUtf8Text + c.fTextByteLength; - SkUnichar unichar = SkUTF8_NextUnicharWithError(&textPtr, textEnd); - if (unichar < 0) { + for (; index < glyphLimit; ++index) { + SkGlyphID gid = glyphs[index]; + if (gid > maxGlyphID) { + continue; + } + if (!font || !font->hasGlyph(gid)) { + // Not yet specified font or need to switch font. + int fontIndex = this->getFontResourceIndex(typeface, gid); + // All preconditions for SkPDFFont::GetFontResource are met. + SkASSERT(fontIndex >= 0); + if (fontIndex < 0) { return; } - if (textPtr < textEnd || // more characters left - glyphLimit > index + 1 || // toUnicode wouldn't work - unichar != map_glyph(glyphToUnicode, glyphs[index])) // test single Unichar map - { - glyphPositioner.flush(); - out->writeText("/Span<</ActualText <"); - SkPDFUtils::WriteUTF16beHex(out, 0xFEFF); // U+FEFF = BYTE ORDER MARK - // the BOM marks this text as UTF-16BE, not PDFDocEncoding. - SkPDFUtils::WriteUTF16beHex(out, unichar); // first char - while (textPtr < textEnd) { - unichar = SkUTF8_NextUnicharWithError(&textPtr, textEnd); - if (unichar < 0) { - break; - } - SkPDFUtils::WriteUTF16beHex(out, unichar); - } - out->writeText("> >> BDC\n"); // begin marked-content sequence - // with an associated property list. - actualText = true; + glyphPositioner.flush(); + update_font(out, fontIndex, textSize); + font = fFontResources[fontIndex]; + SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met. + if (!font) { + return; } + SkASSERT(font->multiByteGlyphs() == multiByteGlyphs); } - for (; index < glyphLimit; ++index) { - SkGlyphID gid = glyphs[index]; - if (gid > maxGlyphID) { - continue; + SkPoint xy{0, 0}; + SkScalar advance{0}; + if (!defaultPositioning) { + advance = advanceScale * glyphCache->getGlyphIDAdvance(gid).fAdvanceX; + xy = SkTextBlob::kFull_Positioning == positioning + ? SkPoint{pos[2 * index], pos[2 * index + 1]} + : SkPoint{pos[index], 0}; + if (alignment != SkPaint::kLeft_Align) { + xy.offset(alignmentFactor * advance, 0); } - if (!font || !font->hasGlyph(gid)) { - // Not yet specified font or need to switch font. - int fontIndex = this->getFontResourceIndex(typeface, gid); - // All preconditions for SkPDFFont::GetFontResource are met. - SkASSERT(fontIndex >= 0); - if (fontIndex < 0) { - return; - } - glyphPositioner.flush(); - update_font(out, fontIndex, textSize); - font = fFontResources[fontIndex]; - SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met. - if (!font) { - return; - } - SkASSERT(font->multiByteGlyphs() == multiByteGlyphs); - } - SkPoint xy = {}; - SkScalar advance = advanceScale * glyphCache->getGlyphIDAdvance(gid).fAdvanceX; - if (!defaultPositioning) { - xy = SkTextBlob::kFull_Positioning == positioning - ? SkPoint{pos[2 * index], pos[2 * index + 1]} - : SkPoint{pos[index], 0}; - if (alignment != SkPaint::kLeft_Align) { - xy.offset(alignmentFactor * advance, 0); - } - // Do a glyph-by-glyph bounds-reject if positions are absolute. - SkRect glyphBounds = get_glyph_bounds_device_space( - gid, glyphCache.get(), textScaleX, textScaleY, - xy + offset, this->ctm()); - if (glyphBounds.isEmpty()) { - if (!contains(clipStackBounds, {glyphBounds.x(), glyphBounds.y()})) { - continue; - } - } else { - if (!clipStackBounds.intersects(glyphBounds)) { - continue; // reject glyphs as out of bounds - } - } - if (!has_outline_glyph(gid, glyphCache.get())) { - fMissingGlyphs.push_back({xy, gid}); + // Do a glyph-by-glyph bounds-reject if positions are absolute. + SkRect glyphBounds = get_glyph_bounds_device_space( + gid, glyphCache.get(), textScaleX, textScaleY, xy + offset, this->ctm()); + if (glyphBounds.isEmpty()) { + if (!contains(clipStackBounds, {glyphBounds.x(), glyphBounds.y()})) { + continue; } } else { - if (!has_outline_glyph(gid, glyphCache.get())) { - fMissingGlyphs.push_back({offset, gid}); + if (!clipStackBounds.intersects(glyphBounds)) { + continue; // reject glyphs as out of bounds } - offset += SkPoint{advance, 0}; } - font->noteGlyphUsage(gid); - - SkGlyphID encodedGlyph = multiByteGlyphs ? gid : font->glyphToPDFFontEncoding(gid); - glyphPositioner.writeGlyph(xy, advance, encodedGlyph); - } - } - } - if (fMissingGlyphs.count() > 0) { - // Fall back on images. - SkPaint scaledGlyphCachePaint; - scaledGlyphCachePaint.setTextSize(paint.getTextSize()); - scaledGlyphCachePaint.setTextScaleX(paint.getTextScaleX()); - scaledGlyphCachePaint.setTextSkewX(paint.getTextSkewX()); - scaledGlyphCachePaint.setTypeface(sk_ref_sp(typeface)); - SkAutoGlyphCache scaledGlyphCache(scaledGlyphCachePaint, nullptr, nullptr); - SkTHashMap<SkPDFCanon::BitmapGlyphKey, SkPDFCanon::BitmapGlyph>* map = - &this->getCanon()->fBitmapGlyphImages; - for (PositionedGlyph positionedGlyph : fMissingGlyphs) { - SkPDFCanon::BitmapGlyphKey key = {typeface->uniqueID(), - paint.getTextSize(), - paint.getTextScaleX(), - paint.getTextSkewX(), - positionedGlyph.fGlyph, - 0}; - SkImage* img = nullptr; - SkIPoint imgOffset = {0, 0}; - if (SkPDFCanon::BitmapGlyph* ptr = map->find(key)) { - img = ptr->fImage.get(); - imgOffset = ptr->fOffset; - } else { - (void)scaledGlyphCache->findImage( - scaledGlyphCache->getGlyphIDMetrics(positionedGlyph.fGlyph)); - SkMask mask; - scaledGlyphCache->getGlyphIDMetrics(positionedGlyph.fGlyph).toMask(&mask); - imgOffset = {mask.fBounds.x(), mask.fBounds.y()}; - img = map->set(key, {image_from_mask(mask), imgOffset})->fImage.get(); - } - if (img) { - SkPoint pt = positionedGlyph.fPos + - SkPoint{(SkScalar)imgOffset.x(), (SkScalar)imgOffset.y()}; - this->drawImage(img, pt.x(), pt.y(), srcPaint); } + font->noteGlyphUsage(gid); + SkGlyphID encodedGlyph = multiByteGlyphs ? gid : font->glyphToPDFFontEncoding(gid); + glyphPositioner.writeGlyph(xy, advance, encodedGlyph); } } } |