blob: 971fdb98b40f977f3b6af7bb98502b13b8636f48 [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.com6cab1a42013-05-29 13:43:31 +000011#include "SkTScopedComPtr.h"
bungeman@google.come8f05922012-08-16 16:13:40 +000012
13#include <dwrite.h>
14#include <limits>
15
16///////////////////////////////////////////////////////////////////////////////
17// SkIDWriteFontFileStream
18
19SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream)
bungeman@google.com6cab1a42013-05-29 13:43:31 +000020 : fFontFileStream(SkRefComPtr(fontFileStream))
bungeman@google.come8f05922012-08-16 16:13:40 +000021 , fPos(0)
22 , fLockedMemory(NULL)
23 , fFragmentLock(NULL) {
bungeman@google.come8f05922012-08-16 16:13:40 +000024}
25
26SkDWriteFontFileStream::~SkDWriteFontFileStream() {
27 if (fFragmentLock) {
28 fFontFileStream->ReleaseFileFragment(fFragmentLock);
29 }
30}
31
bungeman@google.come8f05922012-08-16 16:13:40 +000032size_t SkDWriteFontFileStream::read(void* buffer, size_t size) {
33 HRESULT hr = S_OK;
34
35 if (NULL == buffer) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000036 size_t fileSize = this->getLength();
37
38 if (fPos + size > fileSize) {
39 size_t skipped = fileSize - fPos;
40 fPos = fileSize;
41 return skipped;
bungeman@google.come8f05922012-08-16 16:13:40 +000042 } else {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000043 fPos += size;
44 return size;
bungeman@google.come8f05922012-08-16 16:13:40 +000045 }
46 }
47
48 const void* start;
49 void* fragmentLock;
50 hr = fFontFileStream->ReadFileFragment(&start, fPos, size, &fragmentLock);
51 if (SUCCEEDED(hr)) {
52 memcpy(buffer, start, size);
53 fFontFileStream->ReleaseFileFragment(fragmentLock);
54 fPos += size;
55 return size;
56 }
57
58 //The read may have failed because we asked for too much data.
bungeman@google.com6cab1a42013-05-29 13:43:31 +000059 size_t fileSize = this->getLength();
60 if (fPos + size <= fileSize) {
61 //This means we were within bounds, but failed for some other reason.
62 return 0;
63 }
64
65 size_t read = fileSize - fPos;
66 hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock);
67 if (SUCCEEDED(hr)) {
68 memcpy(buffer, start, read);
69 fFontFileStream->ReleaseFileFragment(fragmentLock);
70 fPos = fileSize;
71 return read;
72 }
73
74 return 0;
75}
76
77bool SkDWriteFontFileStream::isAtEnd() const {
78 return fPos == this->getLength();
79}
80
81bool SkDWriteFontFileStream::rewind() {
82 fPos = 0;
83 return true;
84}
85
86SkDWriteFontFileStream* SkDWriteFontFileStream::duplicate() const {
87 return SkNEW_ARGS(SkDWriteFontFileStream, (fFontFileStream.get()));
88}
89
90size_t SkDWriteFontFileStream::getPosition() const {
91 return fPos;
92}
93
94bool SkDWriteFontFileStream::seek(size_t position) {
95 size_t length = this->getLength();
96 fPos = (position > length) ? length : position;
97 return true;
98}
99
100bool SkDWriteFontFileStream::move(long offset) {
101 return seek(fPos + offset);
102}
103
104SkDWriteFontFileStream* SkDWriteFontFileStream::fork() const {
105 SkAutoTUnref<SkDWriteFontFileStream> that(this->duplicate());
106 that->seek(fPos);
107 return that.detach();
108}
109
110size_t SkDWriteFontFileStream::getLength() const {
111 HRESULT hr = S_OK;
bungeman@google.come8f05922012-08-16 16:13:40 +0000112 UINT64 realFileSize = 0;
113 hr = fFontFileStream->GetFileSize(&realFileSize);
114 if (realFileSize > (std::numeric_limits<size_t>::max)()) {
115 return 0;
116 }
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000117 return static_cast<size_t>(realFileSize);
bungeman@google.come8f05922012-08-16 16:13:40 +0000118}
119
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000120const void* SkDWriteFontFileStream::getMemoryBase() {
121 if (fLockedMemory) {
122 return fLockedMemory;
123 }
124
125 UINT64 fileSize;
126 HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size");
127 HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock),
128 "Could not lock file fragment.");
129 return fLockedMemory;
130}
bungeman@google.come8f05922012-08-16 16:13:40 +0000131
132///////////////////////////////////////////////////////////////////////////////
133// SkIDWriteFontFileStreamWrapper
134
135HRESULT SkDWriteFontFileStreamWrapper::Create(SkStream* stream, SkDWriteFontFileStreamWrapper** streamFontFileStream) {
136 *streamFontFileStream = new SkDWriteFontFileStreamWrapper(stream);
137 if (NULL == streamFontFileStream) {
138 return E_OUTOFMEMORY;
139 }
140 return S_OK;
141}
142
143SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStream* stream)
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000144 : fRefCount(1), fStream(SkRef(stream)) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000145}
146
147HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) {
148 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
149 *ppvObject = this;
150 AddRef();
151 return S_OK;
152 } else {
153 *ppvObject = NULL;
154 return E_NOINTERFACE;
155 }
156}
157
158ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::AddRef() {
159 return InterlockedIncrement(&fRefCount);
160}
161
162ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::Release() {
163 ULONG newCount = InterlockedDecrement(&fRefCount);
164 if (0 == newCount) {
165 delete this;
166 }
167 return newCount;
168}
169
170HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment(
171 void const** fragmentStart,
172 UINT64 fileOffset,
173 UINT64 fragmentSize,
174 void** fragmentContext)
175{
176 // The loader is responsible for doing a bounds check.
177 UINT64 fileSize;
178 this->GetFileSize(&fileSize);
179 if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) {
180 *fragmentStart = NULL;
181 *fragmentContext = NULL;
182 return E_FAIL;
183 }
184
185 if (fileOffset + fragmentSize > (std::numeric_limits<size_t>::max)()) {
186 return E_FAIL;
187 }
188
189 const void* data = fStream->getMemoryBase();
190 if (NULL != data) {
191 *fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(fileOffset);
192 *fragmentContext = NULL;
193
194 } else {
195 //May be called from multiple threads.
196 SkAutoMutexAcquire ama(fStreamMutex);
197
198 *fragmentStart = NULL;
199 *fragmentContext = NULL;
200
201 if (!fStream->rewind()) {
202 return E_FAIL;
203 }
204 if (fStream->skip(static_cast<size_t>(fileOffset)) != fileOffset) {
205 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}