/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "tools/fonts/RandomScalerContext.h" #include "include/core/SkBitmap.h" #include "include/core/SkCanvas.h" #include "include/core/SkDrawable.h" #include "include/core/SkPath.h" #include "include/core/SkStream.h" #include "src/core/SkAdvancedTypefaceMetrics.h" #include "src/core/SkGlyph.h" #include "src/core/SkRectPriv.h" #include "src/core/SkTHash.h" using namespace skia_private; class SkDescriptor; class RandomScalerContext : public SkScalerContext { public: RandomScalerContext(sk_sp, const SkScalerContextEffects&, const SkDescriptor*, bool fFakeIt); protected: GlyphMetrics generateMetrics(const SkGlyph&, SkArenaAlloc*) override; void generateImage(const SkGlyph&, void*) override; bool generatePath(const SkGlyph&, SkPath*, bool*) override; sk_sp generateDrawable(const SkGlyph&) override; void generateFontMetrics(SkFontMetrics*) override; private: SkRandomTypeface* getRandomTypeface() const { return static_cast(this->getTypeface()); } std::unique_ptr fProxy; // Many of the SkGlyphs returned are the same as those created by the fProxy. // When they are not, the originals are kept here. THashMap fProxyGlyphs; bool fFakeIt; }; RandomScalerContext::RandomScalerContext(sk_sp face, const SkScalerContextEffects& effects, const SkDescriptor* desc, bool fakeIt) : SkScalerContext(std::move(face), effects, desc) , fProxy(getRandomTypeface()->proxy()->createScalerContext(SkScalerContextEffects(), desc)) , fFakeIt(fakeIt) { fProxy->forceGenerateImageFromPath(); } SkScalerContext::GlyphMetrics RandomScalerContext::generateMetrics(const SkGlyph& origGlyph, SkArenaAlloc* alloc) { // Here we will change the mask format of the glyph // NOTE: this may be overridden by the base class (e.g. if a mask filter is applied). SkMask::Format format = SkMask::kA8_Format; switch (origGlyph.getGlyphID() % 4) { case 0: format = SkMask::kLCD16_Format; break; case 1: format = SkMask::kA8_Format; break; case 2: format = SkMask::kARGB32_Format; break; case 3: format = SkMask::kBW_Format; break; } auto glyph = fProxy->internalMakeGlyph(origGlyph.getPackedID(), format, alloc); GlyphMetrics mx(SkMask::kA8_Format); mx.advance = glyph.advanceVector(); mx.bounds = glyph.rect(); mx.maskFormat = glyph.maskFormat(); mx.extraBits = glyph.extraBits(); if (fFakeIt || (glyph.getGlyphID() % 4) != 2) { mx.neverRequestPath = glyph.setPathHasBeenCalled() && !glyph.path(); mx.computeFromPath = !mx.neverRequestPath; return mx; } fProxy->getPath(glyph, alloc); if (!glyph.path()) { mx.neverRequestPath = true; return mx; } // The proxy glyph has a path, but this glyph does not. // Stash the proxy glyph so it can be used later. const auto packedID = glyph.getPackedID(); const SkGlyph* proxyGlyph = fProxyGlyphs.set(packedID, std::move(glyph)); const SkPath& proxyPath = *proxyGlyph->path(); mx.neverRequestPath = true; mx.maskFormat = SkMask::kARGB32_Format; mx.advance = proxyGlyph->advanceVector(); mx.extraBits = proxyGlyph->extraBits(); SkRect storage; const SkPaint& paint = this->getRandomTypeface()->paint(); const SkRect& newBounds = paint.doComputeFastBounds(proxyPath.getBounds(), &storage, SkPaint::kFill_Style); newBounds.roundOut(&mx.bounds); return mx; } void RandomScalerContext::generateImage(const SkGlyph& glyph, void* imageBuffer) { if (fFakeIt) { sk_bzero(imageBuffer, glyph.imageSize()); return; } SkGlyph* proxyGlyph = fProxyGlyphs.find(glyph.getPackedID()); if (!proxyGlyph || !proxyGlyph->path()) { fProxy->getImage(glyph); return; } const SkPath& path = *proxyGlyph->path(); const bool hairline = proxyGlyph->pathIsHairline(); SkBitmap bm; bm.installPixels(SkImageInfo::MakeN32Premul(glyph.width(), glyph.height()), imageBuffer, glyph.rowBytes()); bm.eraseColor(0); SkCanvas canvas(bm); canvas.translate(-SkIntToScalar(glyph.left()), -SkIntToScalar(glyph.top())); SkPaint paint = this->getRandomTypeface()->paint(); if (hairline) { // We have a device path with effects already applied which is normally a fill path. // However here we do not have a fill path and there is no area to fill. paint.setStyle(SkPaint::kStroke_Style); paint.setStroke(0); } canvas.drawPath(path, paint); //Need to modify the paint if the devPath is hairline } bool RandomScalerContext::generatePath(const SkGlyph& glyph, SkPath* path, bool* modified) { SkGlyph* shadowProxyGlyph = fProxyGlyphs.find(glyph.getPackedID()); if (shadowProxyGlyph && shadowProxyGlyph->path()) { path->reset(); return false; } return fProxy->generatePath(glyph, path, modified); } sk_sp RandomScalerContext::generateDrawable(const SkGlyph& glyph) { SkGlyph* shadowProxyGlyph = fProxyGlyphs.find(glyph.getPackedID()); if (shadowProxyGlyph && shadowProxyGlyph->path()) { return nullptr; } return fProxy->generateDrawable(glyph); } void RandomScalerContext::generateFontMetrics(SkFontMetrics* metrics) { fProxy->getFontMetrics(metrics); } /////////////////////////////////////////////////////////////////////////////// SkRandomTypeface::SkRandomTypeface(sk_sp proxy, const SkPaint& paint, bool fakeIt) : SkTypeface(proxy->fontStyle(), false) , fProxy(std::move(proxy)) , fPaint(paint) , fFakeIt(fakeIt) {} std::unique_ptr SkRandomTypeface::onCreateScalerContext( const SkScalerContextEffects& effects, const SkDescriptor* desc) const { return std::make_unique( sk_ref_sp(const_cast(this)), effects, desc, fFakeIt); } void SkRandomTypeface::onFilterRec(SkScalerContextRec* rec) const { fProxy->filterRec(rec); rec->setHinting(SkFontHinting::kNone); rec->fMaskFormat = SkMask::kARGB32_Format; } void SkRandomTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const { fProxy->getGlyphToUnicodeMap(glyphToUnicode); } std::unique_ptr SkRandomTypeface::onGetAdvancedMetrics() const { return fProxy->getAdvancedMetrics(); } std::unique_ptr SkRandomTypeface::onOpenStream(int* ttcIndex) const { return fProxy->openStream(ttcIndex); } sk_sp SkRandomTypeface::onMakeClone(const SkFontArguments& args) const { sk_sp proxy = fProxy->makeClone(args); if (!proxy) { return nullptr; } return sk_make_sp(proxy, fPaint, fFakeIt); } void SkRandomTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const { // TODO: anything that uses this typeface isn't correctly serializable, since this typeface // cannot be deserialized. fProxy->getFontDescriptor(desc, isLocal); } void SkRandomTypeface::onCharsToGlyphs(const SkUnichar* uni, int count, SkGlyphID glyphs[]) const { fProxy->unicharsToGlyphs(uni, count, glyphs); } int SkRandomTypeface::onCountGlyphs() const { return fProxy->countGlyphs(); } int SkRandomTypeface::onGetUPEM() const { return fProxy->getUnitsPerEm(); } void SkRandomTypeface::onGetFamilyName(SkString* familyName) const { fProxy->getFamilyName(familyName); } bool SkRandomTypeface::onGetPostScriptName(SkString* postScriptName) const { return fProxy->getPostScriptName(postScriptName); } SkTypeface::LocalizedStrings* SkRandomTypeface::onCreateFamilyNameIterator() const { return fProxy->createFamilyNameIterator(); } void SkRandomTypeface::getPostScriptGlyphNames(SkString* names) const { return fProxy->getPostScriptGlyphNames(names); } bool SkRandomTypeface::onGlyphMaskNeedsCurrentColor() const { return fProxy->glyphMaskNeedsCurrentColor(); } int SkRandomTypeface::onGetVariationDesignPosition( SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const { return fProxy->onGetVariationDesignPosition(coordinates, coordinateCount); } int SkRandomTypeface::onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], int parameterCount) const { return fProxy->onGetVariationDesignParameters(parameters, parameterCount); } int SkRandomTypeface::onGetTableTags(SkFontTableTag tags[]) const { return fProxy->getTableTags(tags); } size_t SkRandomTypeface::onGetTableData(SkFontTableTag tag, size_t offset, size_t length, void* data) const { return fProxy->getTableData(tag, offset, length, data); }