1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/utils/win/SkDWriteFontFileStream.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,232 @@ 1.4 +/* 1.5 + * Copyright 2012 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkTypes.h" 1.12 +#include "SkDWriteFontFileStream.h" 1.13 +#include "SkHRESULT.h" 1.14 +#include "SkTemplates.h" 1.15 +#include "SkTFitsIn.h" 1.16 +#include "SkTScopedComPtr.h" 1.17 + 1.18 +#include <dwrite.h> 1.19 + 1.20 +/////////////////////////////////////////////////////////////////////////////// 1.21 +// SkIDWriteFontFileStream 1.22 + 1.23 +SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream) 1.24 + : fFontFileStream(SkRefComPtr(fontFileStream)) 1.25 + , fPos(0) 1.26 + , fLockedMemory(NULL) 1.27 + , fFragmentLock(NULL) { 1.28 +} 1.29 + 1.30 +SkDWriteFontFileStream::~SkDWriteFontFileStream() { 1.31 + if (fFragmentLock) { 1.32 + fFontFileStream->ReleaseFileFragment(fFragmentLock); 1.33 + } 1.34 +} 1.35 + 1.36 +size_t SkDWriteFontFileStream::read(void* buffer, size_t size) { 1.37 + HRESULT hr = S_OK; 1.38 + 1.39 + if (NULL == buffer) { 1.40 + size_t fileSize = this->getLength(); 1.41 + 1.42 + if (fPos + size > fileSize) { 1.43 + size_t skipped = fileSize - fPos; 1.44 + fPos = fileSize; 1.45 + return skipped; 1.46 + } else { 1.47 + fPos += size; 1.48 + return size; 1.49 + } 1.50 + } 1.51 + 1.52 + const void* start; 1.53 + void* fragmentLock; 1.54 + hr = fFontFileStream->ReadFileFragment(&start, fPos, size, &fragmentLock); 1.55 + if (SUCCEEDED(hr)) { 1.56 + memcpy(buffer, start, size); 1.57 + fFontFileStream->ReleaseFileFragment(fragmentLock); 1.58 + fPos += size; 1.59 + return size; 1.60 + } 1.61 + 1.62 + //The read may have failed because we asked for too much data. 1.63 + size_t fileSize = this->getLength(); 1.64 + if (fPos + size <= fileSize) { 1.65 + //This means we were within bounds, but failed for some other reason. 1.66 + return 0; 1.67 + } 1.68 + 1.69 + size_t read = fileSize - fPos; 1.70 + hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock); 1.71 + if (SUCCEEDED(hr)) { 1.72 + memcpy(buffer, start, read); 1.73 + fFontFileStream->ReleaseFileFragment(fragmentLock); 1.74 + fPos = fileSize; 1.75 + return read; 1.76 + } 1.77 + 1.78 + return 0; 1.79 +} 1.80 + 1.81 +bool SkDWriteFontFileStream::isAtEnd() const { 1.82 + return fPos == this->getLength(); 1.83 +} 1.84 + 1.85 +bool SkDWriteFontFileStream::rewind() { 1.86 + fPos = 0; 1.87 + return true; 1.88 +} 1.89 + 1.90 +SkDWriteFontFileStream* SkDWriteFontFileStream::duplicate() const { 1.91 + return SkNEW_ARGS(SkDWriteFontFileStream, (fFontFileStream.get())); 1.92 +} 1.93 + 1.94 +size_t SkDWriteFontFileStream::getPosition() const { 1.95 + return fPos; 1.96 +} 1.97 + 1.98 +bool SkDWriteFontFileStream::seek(size_t position) { 1.99 + size_t length = this->getLength(); 1.100 + fPos = (position > length) ? length : position; 1.101 + return true; 1.102 +} 1.103 + 1.104 +bool SkDWriteFontFileStream::move(long offset) { 1.105 + return seek(fPos + offset); 1.106 +} 1.107 + 1.108 +SkDWriteFontFileStream* SkDWriteFontFileStream::fork() const { 1.109 + SkAutoTUnref<SkDWriteFontFileStream> that(this->duplicate()); 1.110 + that->seek(fPos); 1.111 + return that.detach(); 1.112 +} 1.113 + 1.114 +size_t SkDWriteFontFileStream::getLength() const { 1.115 + HRESULT hr = S_OK; 1.116 + UINT64 realFileSize = 0; 1.117 + hr = fFontFileStream->GetFileSize(&realFileSize); 1.118 + if (!SkTFitsIn<size_t>(realFileSize)) { 1.119 + return 0; 1.120 + } 1.121 + return static_cast<size_t>(realFileSize); 1.122 +} 1.123 + 1.124 +const void* SkDWriteFontFileStream::getMemoryBase() { 1.125 + if (fLockedMemory) { 1.126 + return fLockedMemory; 1.127 + } 1.128 + 1.129 + UINT64 fileSize; 1.130 + HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size"); 1.131 + HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock), 1.132 + "Could not lock file fragment."); 1.133 + return fLockedMemory; 1.134 +} 1.135 + 1.136 +/////////////////////////////////////////////////////////////////////////////// 1.137 +// SkIDWriteFontFileStreamWrapper 1.138 + 1.139 +HRESULT SkDWriteFontFileStreamWrapper::Create(SkStream* stream, SkDWriteFontFileStreamWrapper** streamFontFileStream) { 1.140 + *streamFontFileStream = new SkDWriteFontFileStreamWrapper(stream); 1.141 + if (NULL == streamFontFileStream) { 1.142 + return E_OUTOFMEMORY; 1.143 + } 1.144 + return S_OK; 1.145 +} 1.146 + 1.147 +SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStream* stream) 1.148 + : fRefCount(1), fStream(SkRef(stream)) { 1.149 +} 1.150 + 1.151 +HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) { 1.152 + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { 1.153 + *ppvObject = this; 1.154 + AddRef(); 1.155 + return S_OK; 1.156 + } else { 1.157 + *ppvObject = NULL; 1.158 + return E_NOINTERFACE; 1.159 + } 1.160 +} 1.161 + 1.162 +ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::AddRef() { 1.163 + return InterlockedIncrement(&fRefCount); 1.164 +} 1.165 + 1.166 +ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::Release() { 1.167 + ULONG newCount = InterlockedDecrement(&fRefCount); 1.168 + if (0 == newCount) { 1.169 + delete this; 1.170 + } 1.171 + return newCount; 1.172 +} 1.173 + 1.174 +HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment( 1.175 + void const** fragmentStart, 1.176 + UINT64 fileOffset, 1.177 + UINT64 fragmentSize, 1.178 + void** fragmentContext) 1.179 +{ 1.180 + // The loader is responsible for doing a bounds check. 1.181 + UINT64 fileSize; 1.182 + this->GetFileSize(&fileSize); 1.183 + if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) { 1.184 + *fragmentStart = NULL; 1.185 + *fragmentContext = NULL; 1.186 + return E_FAIL; 1.187 + } 1.188 + 1.189 + if (!SkTFitsIn<size_t>(fileOffset + fragmentSize)) { 1.190 + return E_FAIL; 1.191 + } 1.192 + 1.193 + const void* data = fStream->getMemoryBase(); 1.194 + if (NULL != data) { 1.195 + *fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(fileOffset); 1.196 + *fragmentContext = NULL; 1.197 + 1.198 + } else { 1.199 + //May be called from multiple threads. 1.200 + SkAutoMutexAcquire ama(fStreamMutex); 1.201 + 1.202 + *fragmentStart = NULL; 1.203 + *fragmentContext = NULL; 1.204 + 1.205 + if (!fStream->rewind()) { 1.206 + return E_FAIL; 1.207 + } 1.208 + if (fStream->skip(static_cast<size_t>(fileOffset)) != fileOffset) { 1.209 + return E_FAIL; 1.210 + } 1.211 + SkAutoTMalloc<uint8_t> streamData(static_cast<size_t>(fragmentSize)); 1.212 + if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) { 1.213 + return E_FAIL; 1.214 + } 1.215 + 1.216 + *fragmentStart = streamData.get(); 1.217 + *fragmentContext = streamData.detach(); 1.218 + } 1.219 + return S_OK; 1.220 +} 1.221 + 1.222 +void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) { 1.223 + sk_free(fragmentContext); 1.224 +} 1.225 + 1.226 +HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) { 1.227 + *fileSize = fStream->getLength(); 1.228 + return S_OK; 1.229 +} 1.230 + 1.231 +HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetLastWriteTime(UINT64* lastWriteTime) { 1.232 + // The concept of last write time does not apply to this loader. 1.233 + *lastWriteTime = 0; 1.234 + return E_NOTIMPL; 1.235 +}