int FindOrAdd(IDWriteFontFileLoader* fontFileLoader, const void* refKey, UINT32 refKeySize) const { SkTScopedComPtr<IUnknown> fontFileLoaderId; HR_GENERAL(fontFileLoader->QueryInterface(&fontFileLoaderId), "Failed to re-convert to IDWriteFontFileLoader.", SkFontIdentity::kInvalidDataId); SkAutoMutexAcquire ama(fDataIdCacheMutex); int count = fDataIdCache.count(); int i; for (i = 0; i < count; ++i) { const DataId& current = fDataIdCache[i]; if (fontFileLoaderId.get() == current.fLoader && refKeySize == current.fKeySize && 0 == memcmp(refKey, current.fKey, refKeySize)) { return i; } } DataId& added = fDataIdCache.push_back(); added.fLoader = fontFileLoaderId.release(); // Ref is passed. added.fKey = sk_malloc_throw(refKeySize); memcpy(added.fKey, refKey, refKeySize); added.fKeySize = refKeySize; return i; }
SkTypeface* onLegacyCreateTypeface(const char requestedFamilyName[], SkFontStyle requestedStyle) const override { SkAutoMutexAcquire ama(fMutex); // Check if this request is already in the request cache. using Request = SkFontRequestCache::Request; SkAutoTDelete<Request> request(Request::Create(requestedFamilyName, requestedStyle)); SkTypeface* face = fCache.findAndRef(request); if (face) { return face; } SkFontConfigInterface::FontIdentity identity; SkString outFamilyName; SkFontStyle outStyle; if (!fFCI->matchFamilyName(requestedFamilyName, requestedStyle, &identity, &outFamilyName, &outStyle)) { return nullptr; } // Check if a typeface with this FontIdentity is already in the FontIdentity cache. face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); if (!face) { face = SkTypeface_FCI::Create(fFCI, identity, outFamilyName, outStyle); // Add this FontIdentity to the FontIdentity cache. fTFCache.add(face); } // Add this request to the request cache. fCache.add(face, request.release()); return face; }
SkTypeface* SkFontMgr_Indirect::createTypefaceFromFontId(const SkFontIdentity& id) const { if (id.fDataId == SkFontIdentity::kInvalidDataId) { return nullptr; } SkAutoMutexAcquire ama(fDataCacheMutex); SkAutoTUnref<SkTypeface> dataTypeface; int dataTypefaceIndex = 0; for (int i = 0; i < fDataCache.count(); ++i) { const DataEntry& entry = fDataCache[i]; if (entry.fDataId == id.fDataId) { if (entry.fTtcIndex == id.fTtcIndex && !entry.fTypeface->weak_expired() && entry.fTypeface->try_ref()) { return entry.fTypeface; } if (dataTypeface.get() == nullptr && !entry.fTypeface->weak_expired() && entry.fTypeface->try_ref()) { dataTypeface.reset(entry.fTypeface); dataTypefaceIndex = entry.fTtcIndex; } } if (entry.fTypeface->weak_expired()) { fDataCache.removeShuffle(i); --i; } } // No exact match, but did find a data match. if (dataTypeface.get() != nullptr) { SkAutoTDelete<SkStreamAsset> stream(dataTypeface->openStream(nullptr)); if (stream.get() != nullptr) { return fImpl->createFromStream(stream.release(), dataTypefaceIndex); } } // No data match, request data and add entry. SkAutoTDelete<SkStreamAsset> stream(fProxy->getData(id.fDataId)); if (stream.get() == nullptr) { return nullptr; } SkAutoTUnref<SkTypeface> typeface(fImpl->createFromStream(stream.release(), id.fTtcIndex)); if (typeface.get() == nullptr) { return nullptr; } DataEntry& newEntry = fDataCache.push_back(); typeface->weak_ref(); newEntry.fDataId = id.fDataId; newEntry.fTtcIndex = id.fTtcIndex; newEntry.fTypeface = typeface.get(); // weak reference passed to new entry. return typeface.release(); }
SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatrix* localM) const { SkASSERT(fPicture && fPicture->width() > 0 && fPicture->height() > 0); SkMatrix m; m.setConcat(matrix, this->getLocalMatrix()); if (localM) { m.preConcat(*localM); } // Use a rotation-invariant scale SkPoint scale; if (!SkDecomposeUpper2x2(m, NULL, &scale, NULL)) { // Decomposition failed, use an approximation. scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m.getSkewX()), SkScalarSqrt(m.getScaleY() * m.getScaleY() + m.getSkewY() * m.getSkewY())); } SkSize scaledSize = SkSize::Make(scale.x() * fPicture->width(), scale.y() * fPicture->height()); SkISize tileSize = scaledSize.toRound(); if (tileSize.isEmpty()) { return NULL; } // The actual scale, compensating for rounding. SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fPicture->width(), SkIntToScalar(tileSize.height()) / fPicture->height()); SkAutoMutexAcquire ama(fCachedBitmapShaderMutex); if (!fCachedBitmapShader || tileScale != fCachedTileScale) { SkBitmap bm; if (!bm.allocN32Pixels(tileSize.width(), tileSize.height())) { return NULL; } bm.eraseColor(SK_ColorTRANSPARENT); SkCanvas canvas(bm); canvas.scale(tileScale.width(), tileScale.height()); canvas.drawPicture(fPicture); fCachedTileScale = tileScale; SkMatrix shaderMatrix = this->getLocalMatrix(); shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy, &shaderMatrix)); } // Increment the ref counter inside the mutex to ensure the returned pointer is still valid. // Otherwise, the pointer may have been overwritten on a different thread before the object's // ref count was incremented. fCachedBitmapShader.get()->ref(); return fCachedBitmapShader; }
SkTypeface* SkFontMgr_DirectWrite::createTypefaceFromDWriteFont( IDWriteFontFace* fontFace, IDWriteFont* font, IDWriteFontFamily* fontFamily) const { SkAutoMutexAcquire ama(fTFCacheMutex); ProtoDWriteTypeface spec = { fontFace, font, fontFamily }; SkTypeface* face = fTFCache.findByProcAndRef(FindByDWriteFont, &spec); if (nullptr == face) { face = DWriteFontTypeface::Create(fFactory.get(), fontFace, font, fontFamily); if (face) { fTFCache.add(face); } } return face; }
HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment( void const** fragmentStart, UINT64 fileOffset, UINT64 fragmentSize, void** fragmentContext) { // The loader is responsible for doing a bounds check. UINT64 fileSize; this->GetFileSize(&fileSize); if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) { *fragmentStart = NULL; *fragmentContext = NULL; return E_FAIL; } if (!SkTFitsIn<size_t>(fileOffset + fragmentSize)) { return E_FAIL; } const void* data = fStream->getMemoryBase(); if (NULL != data) { *fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(fileOffset); *fragmentContext = NULL; } else { //May be called from multiple threads. SkAutoMutexAcquire ama(fStreamMutex); *fragmentStart = NULL; *fragmentContext = NULL; if (!fStream->rewind()) { return E_FAIL; } if (fStream->skip(static_cast<size_t>(fileOffset)) != fileOffset) { return E_FAIL; } SkAutoTMalloc<uint8_t> streamData(static_cast<size_t>(fragmentSize)); if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) { return E_FAIL; } *fragmentStart = streamData.get(); *fragmentContext = streamData.detach(); } return S_OK; }