/* * Copyright 2012 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/SkTypes.h" #if defined(SK_BUILD_FOR_WIN) #include "include/core/SkTypes.h" #include "include/private/SkTFitsIn.h" #include "include/private/SkTemplates.h" #include "src/utils/win/SkDWriteFontFileStream.h" #include "src/utils/win/SkHRESULT.h" #include "src/utils/win/SkTScopedComPtr.h" #include /////////////////////////////////////////////////////////////////////////////// // SkIDWriteFontFileStream SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream) : fFontFileStream(SkRefComPtr(fontFileStream)) , fPos(0) , fLockedMemory(nullptr) , fFragmentLock(nullptr) { } SkDWriteFontFileStream::~SkDWriteFontFileStream() { if (fFragmentLock) { fFontFileStream->ReleaseFileFragment(fFragmentLock); } } size_t SkDWriteFontFileStream::read(void* buffer, size_t size) { HRESULT hr = S_OK; if (nullptr == buffer) { size_t fileSize = this->getLength(); if (fPos + size > fileSize) { size_t skipped = fileSize - fPos; fPos = fileSize; return skipped; } else { fPos += size; return size; } } const void* start; void* fragmentLock; hr = fFontFileStream->ReadFileFragment(&start, fPos, size, &fragmentLock); if (SUCCEEDED(hr)) { memcpy(buffer, start, size); fFontFileStream->ReleaseFileFragment(fragmentLock); fPos += size; return size; } //The read may have failed because we asked for too much data. size_t fileSize = this->getLength(); if (fPos + size <= fileSize) { //This means we were within bounds, but failed for some other reason. return 0; } size_t read = fileSize - fPos; hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock); if (SUCCEEDED(hr)) { memcpy(buffer, start, read); fFontFileStream->ReleaseFileFragment(fragmentLock); fPos = fileSize; return read; } return 0; } bool SkDWriteFontFileStream::isAtEnd() const { return fPos == this->getLength(); } bool SkDWriteFontFileStream::rewind() { fPos = 0; return true; } SkDWriteFontFileStream* SkDWriteFontFileStream::onDuplicate() const { return new SkDWriteFontFileStream(fFontFileStream.get()); } size_t SkDWriteFontFileStream::getPosition() const { return fPos; } bool SkDWriteFontFileStream::seek(size_t position) { size_t length = this->getLength(); fPos = (position > length) ? length : position; return true; } bool SkDWriteFontFileStream::move(long offset) { return seek(fPos + offset); } SkDWriteFontFileStream* SkDWriteFontFileStream::onFork() const { std::unique_ptr that(this->duplicate()); that->seek(fPos); return that.release(); } size_t SkDWriteFontFileStream::getLength() const { HRESULT hr = S_OK; UINT64 realFileSize = 0; hr = fFontFileStream->GetFileSize(&realFileSize); if (!SkTFitsIn(realFileSize)) { return 0; } return static_cast(realFileSize); } const void* SkDWriteFontFileStream::getMemoryBase() { if (fLockedMemory) { return fLockedMemory; } UINT64 fileSize; HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size"); HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock), "Could not lock file fragment."); return fLockedMemory; } /////////////////////////////////////////////////////////////////////////////// // SkIDWriteFontFileStreamWrapper HRESULT SkDWriteFontFileStreamWrapper::Create(SkStreamAsset* stream, SkDWriteFontFileStreamWrapper** streamFontFileStream) { *streamFontFileStream = new SkDWriteFontFileStreamWrapper(stream); if (nullptr == *streamFontFileStream) { return E_OUTOFMEMORY; } return S_OK; } SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStreamAsset* stream) : fRefCount(1), fStream(stream) { } SK_STDMETHODIMP SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) { if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { *ppvObject = this; AddRef(); return S_OK; } else { *ppvObject = nullptr; return E_NOINTERFACE; } } SK_STDMETHODIMP_(ULONG) SkDWriteFontFileStreamWrapper::AddRef() { return InterlockedIncrement(&fRefCount); } SK_STDMETHODIMP_(ULONG) SkDWriteFontFileStreamWrapper::Release() { ULONG newCount = InterlockedDecrement(&fRefCount); if (0 == newCount) { delete this; } return newCount; } SK_STDMETHODIMP 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 = nullptr; *fragmentContext = nullptr; return E_FAIL; } if (!SkTFitsIn(fileOffset + fragmentSize)) { return E_FAIL; } const void* data = fStream->getMemoryBase(); if (data) { *fragmentStart = static_cast(data) + static_cast(fileOffset); *fragmentContext = nullptr; } else { // May be called from multiple threads. SkAutoMutexExclusive ama(fStreamMutex); *fragmentStart = nullptr; *fragmentContext = nullptr; if (!fStream->seek(static_cast(fileOffset))) { return E_FAIL; } SkAutoTMalloc streamData(static_cast(fragmentSize)); if (fStream->read(streamData.get(), static_cast(fragmentSize)) != fragmentSize) { return E_FAIL; } *fragmentStart = streamData.get(); *fragmentContext = streamData.release(); } return S_OK; } SK_STDMETHODIMP_(void) SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) { sk_free(fragmentContext); } SK_STDMETHODIMP SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) { *fileSize = fStream->getLength(); return S_OK; } SK_STDMETHODIMP SkDWriteFontFileStreamWrapper::GetLastWriteTime(UINT64* lastWriteTime) { // The concept of last write time does not apply to this loader. *lastWriteTime = 0; return E_NOTIMPL; } #endif//defined(SK_BUILD_FOR_WIN)