/* * 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 "include/core/SkBitmap.h" #include "include/core/SkCanvas.h" #include "include/core/SkDrawable.h" #include "include/core/SkPath.h" #include "src/core/SkAdvancedTypefaceMetrics.h" #include "src/core/SkGlyph.h" #include "src/core/SkRectPriv.h" #include "tools/fonts/RandomScalerContext.h" class SkDescriptor; class RandomScalerContext : public SkScalerContext { public: RandomScalerContext(sk_sp, const SkScalerContextEffects&, const SkDescriptor*, bool fFakeIt); protected: bool generateAdvance(SkGlyph*) override; void generateMetrics(SkGlyph*, SkArenaAlloc*) override; void generateImage(const SkGlyph&) override; bool generatePath(const SkGlyph&, SkPath*) 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. SkTHashMap 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(); } bool RandomScalerContext::generateAdvance(SkGlyph* glyph) { return fProxy->generateAdvance(glyph); } void RandomScalerContext::generateMetrics(SkGlyph* glyph, 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 (glyph->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; } *glyph = fProxy->internalMakeGlyph(glyph->getPackedID(), format, alloc); if (fFakeIt || (glyph->getGlyphID() % 4) != 2) { return; } fProxy->getPath(*glyph, alloc); if (!glyph->path()) { return; } // The proxy glyph has a path, but this glyph does not. // Stash the proxy glyph so it can be used later. const SkGlyph* proxyGlyph = fProxyGlyphs.set(glyph->getPackedID(), std::move(*glyph)); const SkPath& proxyPath = *proxyGlyph->path(); *glyph = SkGlyph(glyph->getPackedID()); glyph->setPath(alloc, nullptr, false); glyph->fMaskFormat = SkMask::kARGB32_Format; glyph->fAdvanceX = proxyGlyph->fAdvanceX; glyph->fAdvanceY = proxyGlyph->fAdvanceY; SkRect storage; const SkPaint& paint = this->getRandomTypeface()->paint(); const SkRect& newBounds = paint.doComputeFastBounds(proxyPath.getBounds(), &storage, SkPaint::kFill_Style); SkIRect ibounds; newBounds.roundOut(&ibounds); glyph->fLeft = ibounds.fLeft; glyph->fTop = ibounds.fTop; glyph->fWidth = ibounds.width(); glyph->fHeight = ibounds.height(); } void RandomScalerContext::generateImage(const SkGlyph& glyph) { if (fFakeIt) { sk_bzero(glyph.fImage, 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.fWidth, glyph.fHeight), glyph.fImage, glyph.rowBytes()); bm.eraseColor(0); SkCanvas canvas(bm); canvas.translate(-SkIntToScalar(glyph.fLeft), -SkIntToScalar(glyph.fTop)); 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) { SkGlyph* shadowProxyGlyph = fProxyGlyphs.find(glyph.getPackedID()); if (shadowProxyGlyph && shadowProxyGlyph->path()) { path->reset(); return false; } return fProxy->generatePath(glyph, path); } 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); }