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