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