|
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 } |