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