blob: a18760111c0e36239443a8f50d9ea3e59997df81 [file] [log] [blame]
bungeman@google.come8f05922012-08-16 16:13:40 +00001/*
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"
bungeman@google.com11c9a552013-06-03 17:10:35 +000011#include "SkTemplates.h"
bungeman@google.comf5cc5b12013-07-12 18:22:49 +000012#include "SkTFitsIn.h"
bungeman@google.com6cab1a42013-05-29 13:43:31 +000013#include "SkTScopedComPtr.h"
bungeman@google.come8f05922012-08-16 16:13:40 +000014
15#include <dwrite.h>
bungeman@google.come8f05922012-08-16 16:13:40 +000016
17///////////////////////////////////////////////////////////////////////////////
18// SkIDWriteFontFileStream
19
20SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream)
bungeman@google.com6cab1a42013-05-29 13:43:31 +000021 : fFontFileStream(SkRefComPtr(fontFileStream))
bungeman@google.come8f05922012-08-16 16:13:40 +000022 , fPos(0)
23 , fLockedMemory(NULL)
24 , fFragmentLock(NULL) {
bungeman@google.come8f05922012-08-16 16:13:40 +000025}
26
27SkDWriteFontFileStream::~SkDWriteFontFileStream() {
28 if (fFragmentLock) {
29 fFontFileStream->ReleaseFileFragment(fFragmentLock);
30 }
31}
32
bungeman@google.come8f05922012-08-16 16:13:40 +000033size_t SkDWriteFontFileStream::read(void* buffer, size_t size) {
34 HRESULT hr = S_OK;
35
36 if (NULL == buffer) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000037 size_t fileSize = this->getLength();
38
39 if (fPos + size > fileSize) {
40 size_t skipped = fileSize - fPos;
41 fPos = fileSize;
42 return skipped;
bungeman@google.come8f05922012-08-16 16:13:40 +000043 } else {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000044 fPos += size;
45 return size;
bungeman@google.come8f05922012-08-16 16:13:40 +000046 }
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.
bungeman@google.com6cab1a42013-05-29 13:43:31 +000060 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
78bool SkDWriteFontFileStream::isAtEnd() const {
79 return fPos == this->getLength();
80}
81
82bool SkDWriteFontFileStream::rewind() {
83 fPos = 0;
84 return true;
85}
86
87SkDWriteFontFileStream* SkDWriteFontFileStream::duplicate() const {
88 return SkNEW_ARGS(SkDWriteFontFileStream, (fFontFileStream.get()));
89}
90
91size_t SkDWriteFontFileStream::getPosition() const {
92 return fPos;
93}
94
95bool SkDWriteFontFileStream::seek(size_t position) {
96 size_t length = this->getLength();
97 fPos = (position > length) ? length : position;
98 return true;
99}
100
101bool SkDWriteFontFileStream::move(long offset) {
102 return seek(fPos + offset);
103}
104
105SkDWriteFontFileStream* SkDWriteFontFileStream::fork() const {
bungeman2dca8172015-01-22 06:08:31 -0800106 SkAutoTDelete<SkDWriteFontFileStream> that(this->duplicate());
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000107 that->seek(fPos);
108 return that.detach();
109}
110
111size_t SkDWriteFontFileStream::getLength() const {
112 HRESULT hr = S_OK;
bungeman@google.come8f05922012-08-16 16:13:40 +0000113 UINT64 realFileSize = 0;
114 hr = fFontFileStream->GetFileSize(&realFileSize);
bungeman@google.com11c9a552013-06-03 17:10:35 +0000115 if (!SkTFitsIn<size_t>(realFileSize)) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000116 return 0;
117 }
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000118 return static_cast<size_t>(realFileSize);
bungeman@google.come8f05922012-08-16 16:13:40 +0000119}
120
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000121const 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}
bungeman@google.come8f05922012-08-16 16:13:40 +0000132
133///////////////////////////////////////////////////////////////////////////////
134// SkIDWriteFontFileStreamWrapper
135
bungeman0babd3c2015-02-18 11:01:05 -0800136HRESULT SkDWriteFontFileStreamWrapper::Create(SkStreamAsset* stream,
137 SkDWriteFontFileStreamWrapper** streamFontFileStream)
138{
bungeman@google.come8f05922012-08-16 16:13:40 +0000139 *streamFontFileStream = new SkDWriteFontFileStreamWrapper(stream);
140 if (NULL == streamFontFileStream) {
141 return E_OUTOFMEMORY;
142 }
143 return S_OK;
144}
145
bungeman0babd3c2015-02-18 11:01:05 -0800146SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStreamAsset* stream)
scroggoa1193e42015-01-21 12:09:53 -0800147 : fRefCount(1), fStream(stream) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000148}
149
150HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) {
151 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
152 *ppvObject = this;
153 AddRef();
154 return S_OK;
155 } else {
156 *ppvObject = NULL;
157 return E_NOINTERFACE;
158 }
159}
160
161ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::AddRef() {
162 return InterlockedIncrement(&fRefCount);
163}
164
165ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::Release() {
166 ULONG newCount = InterlockedDecrement(&fRefCount);
167 if (0 == newCount) {
168 delete this;
169 }
170 return newCount;
171}
172
173HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment(
174 void const** fragmentStart,
175 UINT64 fileOffset,
176 UINT64 fragmentSize,
177 void** fragmentContext)
178{
179 // The loader is responsible for doing a bounds check.
180 UINT64 fileSize;
181 this->GetFileSize(&fileSize);
182 if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) {
183 *fragmentStart = NULL;
184 *fragmentContext = NULL;
185 return E_FAIL;
186 }
187
bungeman@google.comf5cc5b12013-07-12 18:22:49 +0000188 if (!SkTFitsIn<size_t>(fileOffset + fragmentSize)) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000189 return E_FAIL;
190 }
191
192 const void* data = fStream->getMemoryBase();
bsalomon49f085d2014-09-05 13:34:00 -0700193 if (data) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000194 *fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(fileOffset);
195 *fragmentContext = NULL;
196
197 } else {
bungeman0babd3c2015-02-18 11:01:05 -0800198 // May be called from multiple threads.
bungeman@google.come8f05922012-08-16 16:13:40 +0000199 SkAutoMutexAcquire ama(fStreamMutex);
200
201 *fragmentStart = NULL;
202 *fragmentContext = NULL;
203
bungeman0babd3c2015-02-18 11:01:05 -0800204 if (!fStream->seek(static_cast<size_t>(fileOffset))) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000205 return E_FAIL;
206 }
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000207 SkAutoTMalloc<uint8_t> streamData(static_cast<size_t>(fragmentSize));
bungeman@google.come8f05922012-08-16 16:13:40 +0000208 if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) {
209 return E_FAIL;
210 }
211
212 *fragmentStart = streamData.get();
213 *fragmentContext = streamData.detach();
214 }
215 return S_OK;
216}
217
218void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000219 sk_free(fragmentContext);
bungeman@google.come8f05922012-08-16 16:13:40 +0000220}
221
222HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) {
223 *fileSize = fStream->getLength();
224 return S_OK;
225}
226
227HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetLastWriteTime(UINT64* lastWriteTime) {
228 // The concept of last write time does not apply to this loader.
229 *lastWriteTime = 0;
230 return E_NOTIMPL;
231}