2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
9 #include "SkDWriteFontFileStream.h"
10 #include "SkHRESULT.h"
11 #include "SkTemplates.h"
12 #include "SkTFitsIn.h"
13 #include "SkTScopedComPtr.h"
17 ///////////////////////////////////////////////////////////////////////////////
18 // SkIDWriteFontFileStream
20 SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream)
21 : fFontFileStream(SkRefComPtr(fontFileStream))
24 , fFragmentLock(NULL) {
27 SkDWriteFontFileStream::~SkDWriteFontFileStream() {
29 fFontFileStream->ReleaseFileFragment(fFragmentLock);
33 size_t SkDWriteFontFileStream::read(void* buffer, size_t size) {
37 size_t fileSize = this->getLength();
39 if (fPos + size > fileSize) {
40 size_t skipped = fileSize - fPos;
51 hr = fFontFileStream->ReadFileFragment(&start, fPos, size, &fragmentLock);
53 memcpy(buffer, start, size);
54 fFontFileStream->ReleaseFileFragment(fragmentLock);
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.
66 size_t read = fileSize - fPos;
67 hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock);
69 memcpy(buffer, start, read);
70 fFontFileStream->ReleaseFileFragment(fragmentLock);
78 bool SkDWriteFontFileStream::isAtEnd() const {
79 return fPos == this->getLength();
82 bool SkDWriteFontFileStream::rewind() {
87 SkDWriteFontFileStream* SkDWriteFontFileStream::duplicate() const {
88 return SkNEW_ARGS(SkDWriteFontFileStream, (fFontFileStream.get()));
91 size_t SkDWriteFontFileStream::getPosition() const {
95 bool SkDWriteFontFileStream::seek(size_t position) {
96 size_t length = this->getLength();
97 fPos = (position > length) ? length : position;
101 bool SkDWriteFontFileStream::move(long offset) {
102 return seek(fPos + offset);
105 SkDWriteFontFileStream* SkDWriteFontFileStream::fork() const {
106 SkAutoTUnref<SkDWriteFontFileStream> that(this->duplicate());
108 return that.detach();
111 size_t SkDWriteFontFileStream::getLength() const {
113 UINT64 realFileSize = 0;
114 hr = fFontFileStream->GetFileSize(&realFileSize);
115 if (!SkTFitsIn<size_t>(realFileSize)) {
118 return static_cast<size_t>(realFileSize);
121 const void* SkDWriteFontFileStream::getMemoryBase() {
123 return fLockedMemory;
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;
133 ///////////////////////////////////////////////////////////////////////////////
134 // SkIDWriteFontFileStreamWrapper
136 HRESULT SkDWriteFontFileStreamWrapper::Create(SkStream* stream, SkDWriteFontFileStreamWrapper** streamFontFileStream) {
137 *streamFontFileStream = new SkDWriteFontFileStreamWrapper(stream);
138 if (NULL == streamFontFileStream) {
139 return E_OUTOFMEMORY;
144 SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStream* stream)
145 : fRefCount(1), fStream(SkRef(stream)) {
148 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) {
149 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
155 return E_NOINTERFACE;
159 ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::AddRef() {
160 return InterlockedIncrement(&fRefCount);
163 ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::Release() {
164 ULONG newCount = InterlockedDecrement(&fRefCount);
171 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment(
172 void const** fragmentStart,
175 void** fragmentContext)
177 // The loader is responsible for doing a bounds check.
179 this->GetFileSize(&fileSize);
180 if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) {
181 *fragmentStart = NULL;
182 *fragmentContext = NULL;
186 if (!SkTFitsIn<size_t>(fileOffset + fragmentSize)) {
190 const void* data = fStream->getMemoryBase();
192 *fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(fileOffset);
193 *fragmentContext = NULL;
196 //May be called from multiple threads.
197 SkAutoMutexAcquire ama(fStreamMutex);
199 *fragmentStart = NULL;
200 *fragmentContext = NULL;
202 if (!fStream->rewind()) {
205 if (fStream->skip(static_cast<size_t>(fileOffset)) != fileOffset) {
208 SkAutoTMalloc<uint8_t> streamData(static_cast<size_t>(fragmentSize));
209 if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) {
213 *fragmentStart = streamData.get();
214 *fragmentContext = streamData.detach();
219 void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) {
220 sk_free(fragmentContext);
223 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) {
224 *fileSize = fStream->getLength();
228 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetLastWriteTime(UINT64* lastWriteTime) {
229 // The concept of last write time does not apply to this loader.