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