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_WIN) 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 22 SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream) 23 : fFontFileStream(SkRefComPtr(fontFileStream)) 24 , fPos(0) 25 , fLockedMemory(nullptr) 26 , fFragmentLock(nullptr) { 27 } 28 29 SkDWriteFontFileStream::~SkDWriteFontFileStream() { 30 if (fFragmentLock) { 31 fFontFileStream->ReleaseFileFragment(fFragmentLock); 32 } 33 } 34 35 size_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 80 bool SkDWriteFontFileStream::isAtEnd() const { 81 return fPos == this->getLength(); 82 } 83 84 bool SkDWriteFontFileStream::rewind() { 85 fPos = 0; 86 return true; 87 } 88 89 SkDWriteFontFileStream* SkDWriteFontFileStream::onDuplicate() const { 90 return new SkDWriteFontFileStream(fFontFileStream.get()); 91 } 92 93 size_t SkDWriteFontFileStream::getPosition() const { 94 return fPos; 95 } 96 97 bool SkDWriteFontFileStream::seek(size_t position) { 98 size_t length = this->getLength(); 99 fPos = (position > length) ? length : position; 100 return true; 101 } 102 103 bool SkDWriteFontFileStream::move(long offset) { 104 return seek(fPos + offset); 105 } 106 107 SkDWriteFontFileStream* SkDWriteFontFileStream::onFork() const { 108 std::unique_ptr<SkDWriteFontFileStream> that(this->duplicate()); 109 that->seek(fPos); 110 return that.release(); 111 } 112 113 size_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 123 const 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 138 HRESULT 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 148 SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStreamAsset* stream) 149 : fRefCount(1), fStream(stream) { 150 } 151 152 HRESULT 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 163 ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::AddRef() { 164 return InterlockedIncrement(&fRefCount); 165 } 166 167 ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::Release() { 168 ULONG newCount = InterlockedDecrement(&fRefCount); 169 if (0 == newCount) { 170 delete this; 171 } 172 return newCount; 173 } 174 175 HRESULT 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.release(); 216 } 217 return S_OK; 218 } 219 220 void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) { 221 sk_free(fragmentContext); 222 } 223 224 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) { 225 *fileSize = fStream->getLength(); 226 return S_OK; 227 } 228 229 HRESULT 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_WIN) 236