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