1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 8cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_WIN) 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 11cb93a386Sopenharmony_ci#include "include/private/SkTFitsIn.h" 12cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 13cb93a386Sopenharmony_ci#include "src/utils/win/SkDWriteFontFileStream.h" 14cb93a386Sopenharmony_ci#include "src/utils/win/SkHRESULT.h" 15cb93a386Sopenharmony_ci#include "src/utils/win/SkTScopedComPtr.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci#include <dwrite.h> 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 20cb93a386Sopenharmony_ci// SkIDWriteFontFileStream 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ciSkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream) 23cb93a386Sopenharmony_ci : fFontFileStream(SkRefComPtr(fontFileStream)) 24cb93a386Sopenharmony_ci , fPos(0) 25cb93a386Sopenharmony_ci , fLockedMemory(nullptr) 26cb93a386Sopenharmony_ci , fFragmentLock(nullptr) { 27cb93a386Sopenharmony_ci} 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ciSkDWriteFontFileStream::~SkDWriteFontFileStream() { 30cb93a386Sopenharmony_ci if (fFragmentLock) { 31cb93a386Sopenharmony_ci fFontFileStream->ReleaseFileFragment(fFragmentLock); 32cb93a386Sopenharmony_ci } 33cb93a386Sopenharmony_ci} 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_cisize_t SkDWriteFontFileStream::read(void* buffer, size_t size) { 36cb93a386Sopenharmony_ci HRESULT hr = S_OK; 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci if (nullptr == buffer) { 39cb93a386Sopenharmony_ci size_t fileSize = this->getLength(); 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci if (fPos + size > fileSize) { 42cb93a386Sopenharmony_ci size_t skipped = fileSize - fPos; 43cb93a386Sopenharmony_ci fPos = fileSize; 44cb93a386Sopenharmony_ci return skipped; 45cb93a386Sopenharmony_ci } else { 46cb93a386Sopenharmony_ci fPos += size; 47cb93a386Sopenharmony_ci return size; 48cb93a386Sopenharmony_ci } 49cb93a386Sopenharmony_ci } 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci const void* start; 52cb93a386Sopenharmony_ci void* fragmentLock; 53cb93a386Sopenharmony_ci hr = fFontFileStream->ReadFileFragment(&start, fPos, size, &fragmentLock); 54cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 55cb93a386Sopenharmony_ci memcpy(buffer, start, size); 56cb93a386Sopenharmony_ci fFontFileStream->ReleaseFileFragment(fragmentLock); 57cb93a386Sopenharmony_ci fPos += size; 58cb93a386Sopenharmony_ci return size; 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci //The read may have failed because we asked for too much data. 62cb93a386Sopenharmony_ci size_t fileSize = this->getLength(); 63cb93a386Sopenharmony_ci if (fPos + size <= fileSize) { 64cb93a386Sopenharmony_ci //This means we were within bounds, but failed for some other reason. 65cb93a386Sopenharmony_ci return 0; 66cb93a386Sopenharmony_ci } 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci size_t read = fileSize - fPos; 69cb93a386Sopenharmony_ci hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock); 70cb93a386Sopenharmony_ci if (SUCCEEDED(hr)) { 71cb93a386Sopenharmony_ci memcpy(buffer, start, read); 72cb93a386Sopenharmony_ci fFontFileStream->ReleaseFileFragment(fragmentLock); 73cb93a386Sopenharmony_ci fPos = fileSize; 74cb93a386Sopenharmony_ci return read; 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci return 0; 78cb93a386Sopenharmony_ci} 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_cibool SkDWriteFontFileStream::isAtEnd() const { 81cb93a386Sopenharmony_ci return fPos == this->getLength(); 82cb93a386Sopenharmony_ci} 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_cibool SkDWriteFontFileStream::rewind() { 85cb93a386Sopenharmony_ci fPos = 0; 86cb93a386Sopenharmony_ci return true; 87cb93a386Sopenharmony_ci} 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ciSkDWriteFontFileStream* SkDWriteFontFileStream::onDuplicate() const { 90cb93a386Sopenharmony_ci return new SkDWriteFontFileStream(fFontFileStream.get()); 91cb93a386Sopenharmony_ci} 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_cisize_t SkDWriteFontFileStream::getPosition() const { 94cb93a386Sopenharmony_ci return fPos; 95cb93a386Sopenharmony_ci} 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_cibool SkDWriteFontFileStream::seek(size_t position) { 98cb93a386Sopenharmony_ci size_t length = this->getLength(); 99cb93a386Sopenharmony_ci fPos = (position > length) ? length : position; 100cb93a386Sopenharmony_ci return true; 101cb93a386Sopenharmony_ci} 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_cibool SkDWriteFontFileStream::move(long offset) { 104cb93a386Sopenharmony_ci return seek(fPos + offset); 105cb93a386Sopenharmony_ci} 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ciSkDWriteFontFileStream* SkDWriteFontFileStream::onFork() const { 108cb93a386Sopenharmony_ci std::unique_ptr<SkDWriteFontFileStream> that(this->duplicate()); 109cb93a386Sopenharmony_ci that->seek(fPos); 110cb93a386Sopenharmony_ci return that.release(); 111cb93a386Sopenharmony_ci} 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_cisize_t SkDWriteFontFileStream::getLength() const { 114cb93a386Sopenharmony_ci UINT64 realFileSize = 0; 115cb93a386Sopenharmony_ci fFontFileStream->GetFileSize(&realFileSize); 116cb93a386Sopenharmony_ci if (!SkTFitsIn<size_t>(realFileSize)) { 117cb93a386Sopenharmony_ci return 0; 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci return static_cast<size_t>(realFileSize); 120cb93a386Sopenharmony_ci} 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ciconst void* SkDWriteFontFileStream::getMemoryBase() { 123cb93a386Sopenharmony_ci if (fLockedMemory) { 124cb93a386Sopenharmony_ci return fLockedMemory; 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_ci UINT64 fileSize; 128cb93a386Sopenharmony_ci HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size"); 129cb93a386Sopenharmony_ci HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock), 130cb93a386Sopenharmony_ci "Could not lock file fragment."); 131cb93a386Sopenharmony_ci return fLockedMemory; 132cb93a386Sopenharmony_ci} 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 135cb93a386Sopenharmony_ci// SkIDWriteFontFileStreamWrapper 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ciHRESULT SkDWriteFontFileStreamWrapper::Create(SkStreamAsset* stream, 138cb93a386Sopenharmony_ci SkDWriteFontFileStreamWrapper** streamFontFileStream) 139cb93a386Sopenharmony_ci{ 140cb93a386Sopenharmony_ci *streamFontFileStream = new SkDWriteFontFileStreamWrapper(stream); 141cb93a386Sopenharmony_ci if (nullptr == *streamFontFileStream) { 142cb93a386Sopenharmony_ci return E_OUTOFMEMORY; 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci return S_OK; 145cb93a386Sopenharmony_ci} 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ciSkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStreamAsset* stream) 148cb93a386Sopenharmony_ci : fRefCount(1), fStream(stream) { 149cb93a386Sopenharmony_ci} 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ciSK_STDMETHODIMP SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) { 152cb93a386Sopenharmony_ci if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { 153cb93a386Sopenharmony_ci *ppvObject = this; 154cb93a386Sopenharmony_ci AddRef(); 155cb93a386Sopenharmony_ci return S_OK; 156cb93a386Sopenharmony_ci } else { 157cb93a386Sopenharmony_ci *ppvObject = nullptr; 158cb93a386Sopenharmony_ci return E_NOINTERFACE; 159cb93a386Sopenharmony_ci } 160cb93a386Sopenharmony_ci} 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ciSK_STDMETHODIMP_(ULONG) SkDWriteFontFileStreamWrapper::AddRef() { 163cb93a386Sopenharmony_ci return InterlockedIncrement(&fRefCount); 164cb93a386Sopenharmony_ci} 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ciSK_STDMETHODIMP_(ULONG) SkDWriteFontFileStreamWrapper::Release() { 167cb93a386Sopenharmony_ci ULONG newCount = InterlockedDecrement(&fRefCount); 168cb93a386Sopenharmony_ci if (0 == newCount) { 169cb93a386Sopenharmony_ci delete this; 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci return newCount; 172cb93a386Sopenharmony_ci} 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ciSK_STDMETHODIMP SkDWriteFontFileStreamWrapper::ReadFileFragment( 175cb93a386Sopenharmony_ci void const** fragmentStart, 176cb93a386Sopenharmony_ci UINT64 fileOffset, 177cb93a386Sopenharmony_ci UINT64 fragmentSize, 178cb93a386Sopenharmony_ci void** fragmentContext) 179cb93a386Sopenharmony_ci{ 180cb93a386Sopenharmony_ci // The loader is responsible for doing a bounds check. 181cb93a386Sopenharmony_ci UINT64 fileSize; 182cb93a386Sopenharmony_ci this->GetFileSize(&fileSize); 183cb93a386Sopenharmony_ci if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) { 184cb93a386Sopenharmony_ci *fragmentStart = nullptr; 185cb93a386Sopenharmony_ci *fragmentContext = nullptr; 186cb93a386Sopenharmony_ci return E_FAIL; 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ci if (!SkTFitsIn<size_t>(fileOffset + fragmentSize)) { 190cb93a386Sopenharmony_ci return E_FAIL; 191cb93a386Sopenharmony_ci } 192cb93a386Sopenharmony_ci 193cb93a386Sopenharmony_ci const void* data = fStream->getMemoryBase(); 194cb93a386Sopenharmony_ci if (data) { 195cb93a386Sopenharmony_ci *fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(fileOffset); 196cb93a386Sopenharmony_ci *fragmentContext = nullptr; 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci } else { 199cb93a386Sopenharmony_ci // May be called from multiple threads. 200cb93a386Sopenharmony_ci SkAutoMutexExclusive ama(fStreamMutex); 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_ci *fragmentStart = nullptr; 203cb93a386Sopenharmony_ci *fragmentContext = nullptr; 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_ci if (!fStream->seek(static_cast<size_t>(fileOffset))) { 206cb93a386Sopenharmony_ci return E_FAIL; 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci SkAutoTMalloc<uint8_t> streamData(static_cast<size_t>(fragmentSize)); 209cb93a386Sopenharmony_ci if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) { 210cb93a386Sopenharmony_ci return E_FAIL; 211cb93a386Sopenharmony_ci } 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_ci *fragmentStart = streamData.get(); 214cb93a386Sopenharmony_ci *fragmentContext = streamData.release(); 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci return S_OK; 217cb93a386Sopenharmony_ci} 218cb93a386Sopenharmony_ci 219cb93a386Sopenharmony_ciSK_STDMETHODIMP_(void) SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) { 220cb93a386Sopenharmony_ci sk_free(fragmentContext); 221cb93a386Sopenharmony_ci} 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ciSK_STDMETHODIMP SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) { 224cb93a386Sopenharmony_ci *fileSize = fStream->getLength(); 225cb93a386Sopenharmony_ci return S_OK; 226cb93a386Sopenharmony_ci} 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ciSK_STDMETHODIMP SkDWriteFontFileStreamWrapper::GetLastWriteTime(UINT64* lastWriteTime) { 229cb93a386Sopenharmony_ci // The concept of last write time does not apply to this loader. 230cb93a386Sopenharmony_ci *lastWriteTime = 0; 231cb93a386Sopenharmony_ci return E_NOTIMPL; 232cb93a386Sopenharmony_ci} 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci#endif//defined(SK_BUILD_FOR_WIN) 235