blob: a43e1634814c1e3cca0139b0273a9a2fe67603c9 [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 */
mtklein1ee76512015-11-02 10:20:27 -08007#include "SkTypes.h"
8#if defined(SK_BUILD_FOR_WIN32)
bungeman@google.come8f05922012-08-16 16:13:40 +00009
10#include "SkTypes.h"
11#include "SkDWriteFontFileStream.h"
12#include "SkHRESULT.h"
bungeman@google.com11c9a552013-06-03 17:10:35 +000013#include "SkTemplates.h"
bungeman@google.comf5cc5b12013-07-12 18:22:49 +000014#include "SkTFitsIn.h"
bungeman@google.com6cab1a42013-05-29 13:43:31 +000015#include "SkTScopedComPtr.h"
bungeman@google.come8f05922012-08-16 16:13:40 +000016
17#include <dwrite.h>
bungeman@google.come8f05922012-08-16 16:13:40 +000018
19///////////////////////////////////////////////////////////////////////////////
20// SkIDWriteFontFileStream
21
22SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream)
bungeman@google.com6cab1a42013-05-29 13:43:31 +000023 : fFontFileStream(SkRefComPtr(fontFileStream))
bungeman@google.come8f05922012-08-16 16:13:40 +000024 , fPos(0)
halcanary96fcdcc2015-08-27 07:41:13 -070025 , fLockedMemory(nullptr)
26 , fFragmentLock(nullptr) {
bungeman@google.come8f05922012-08-16 16:13:40 +000027}
28
29SkDWriteFontFileStream::~SkDWriteFontFileStream() {
30 if (fFragmentLock) {
31 fFontFileStream->ReleaseFileFragment(fFragmentLock);
32 }
33}
34
bungeman@google.come8f05922012-08-16 16:13:40 +000035size_t SkDWriteFontFileStream::read(void* buffer, size_t size) {
36 HRESULT hr = S_OK;
37
halcanary96fcdcc2015-08-27 07:41:13 -070038 if (nullptr == buffer) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000039 size_t fileSize = this->getLength();
40
41 if (fPos + size > fileSize) {
42 size_t skipped = fileSize - fPos;
43 fPos = fileSize;
44 return skipped;
bungeman@google.come8f05922012-08-16 16:13:40 +000045 } else {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000046 fPos += size;
47 return size;
bungeman@google.come8f05922012-08-16 16:13:40 +000048 }
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.
bungeman@google.com6cab1a42013-05-29 13:43:31 +000062 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
80bool SkDWriteFontFileStream::isAtEnd() const {
81 return fPos == this->getLength();
82}
83
84bool SkDWriteFontFileStream::rewind() {
85 fPos = 0;
86 return true;
87}
88
Mike Reed98c5d922017-09-15 21:39:47 -040089#ifdef SK_SUPPORT_LEGACY_STREAM_API
90SkDWriteFontFileStream* SkDWriteFontFileStream::duplicate() const
91#else
92SkDWriteFontFileStream* SkDWriteFontFileStream::onDuplicate() const
93#endif
94{
halcanary385fe4d2015-08-26 13:07:48 -070095 return new SkDWriteFontFileStream(fFontFileStream.get());
bungeman@google.com6cab1a42013-05-29 13:43:31 +000096}
97
98size_t SkDWriteFontFileStream::getPosition() const {
99 return fPos;
100}
101
102bool SkDWriteFontFileStream::seek(size_t position) {
103 size_t length = this->getLength();
104 fPos = (position > length) ? length : position;
105 return true;
106}
107
108bool SkDWriteFontFileStream::move(long offset) {
109 return seek(fPos + offset);
110}
111
Mike Reed98c5d922017-09-15 21:39:47 -0400112#ifdef SK_SUPPORT_LEGACY_STREAM_API
113SkDWriteFontFileStream* SkDWriteFontFileStream::fork() const
114#else
115SkDWriteFontFileStream* SkDWriteFontFileStream::onFork() const
116#endif
117{
Ben Wagner145dbcd2016-11-03 14:40:50 -0400118 std::unique_ptr<SkDWriteFontFileStream> that(this->duplicate());
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000119 that->seek(fPos);
mtklein18300a32016-03-16 13:53:35 -0700120 return that.release();
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000121}
122
123size_t SkDWriteFontFileStream::getLength() const {
124 HRESULT hr = S_OK;
bungeman@google.come8f05922012-08-16 16:13:40 +0000125 UINT64 realFileSize = 0;
126 hr = fFontFileStream->GetFileSize(&realFileSize);
bungeman@google.com11c9a552013-06-03 17:10:35 +0000127 if (!SkTFitsIn<size_t>(realFileSize)) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000128 return 0;
129 }
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000130 return static_cast<size_t>(realFileSize);
bungeman@google.come8f05922012-08-16 16:13:40 +0000131}
132
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000133const void* SkDWriteFontFileStream::getMemoryBase() {
134 if (fLockedMemory) {
135 return fLockedMemory;
136 }
137
138 UINT64 fileSize;
139 HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size");
140 HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock),
141 "Could not lock file fragment.");
142 return fLockedMemory;
143}
bungeman@google.come8f05922012-08-16 16:13:40 +0000144
145///////////////////////////////////////////////////////////////////////////////
146// SkIDWriteFontFileStreamWrapper
147
bungeman0babd3c2015-02-18 11:01:05 -0800148HRESULT SkDWriteFontFileStreamWrapper::Create(SkStreamAsset* stream,
149 SkDWriteFontFileStreamWrapper** streamFontFileStream)
150{
bungeman@google.come8f05922012-08-16 16:13:40 +0000151 *streamFontFileStream = new SkDWriteFontFileStreamWrapper(stream);
lsalzman2af45992016-06-07 19:08:57 -0700152 if (nullptr == *streamFontFileStream) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000153 return E_OUTOFMEMORY;
154 }
155 return S_OK;
156}
157
bungeman0babd3c2015-02-18 11:01:05 -0800158SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStreamAsset* stream)
scroggoa1193e42015-01-21 12:09:53 -0800159 : fRefCount(1), fStream(stream) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000160}
161
162HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) {
163 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
164 *ppvObject = this;
165 AddRef();
166 return S_OK;
167 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700168 *ppvObject = nullptr;
bungeman@google.come8f05922012-08-16 16:13:40 +0000169 return E_NOINTERFACE;
170 }
171}
172
173ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::AddRef() {
174 return InterlockedIncrement(&fRefCount);
175}
176
177ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::Release() {
178 ULONG newCount = InterlockedDecrement(&fRefCount);
179 if (0 == newCount) {
180 delete this;
181 }
182 return newCount;
183}
184
185HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment(
186 void const** fragmentStart,
187 UINT64 fileOffset,
188 UINT64 fragmentSize,
189 void** fragmentContext)
190{
191 // The loader is responsible for doing a bounds check.
192 UINT64 fileSize;
193 this->GetFileSize(&fileSize);
194 if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) {
halcanary96fcdcc2015-08-27 07:41:13 -0700195 *fragmentStart = nullptr;
196 *fragmentContext = nullptr;
bungeman@google.come8f05922012-08-16 16:13:40 +0000197 return E_FAIL;
198 }
199
bungeman@google.comf5cc5b12013-07-12 18:22:49 +0000200 if (!SkTFitsIn<size_t>(fileOffset + fragmentSize)) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000201 return E_FAIL;
202 }
203
204 const void* data = fStream->getMemoryBase();
bsalomon49f085d2014-09-05 13:34:00 -0700205 if (data) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000206 *fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(fileOffset);
halcanary96fcdcc2015-08-27 07:41:13 -0700207 *fragmentContext = nullptr;
bungeman@google.come8f05922012-08-16 16:13:40 +0000208
209 } else {
bungeman0babd3c2015-02-18 11:01:05 -0800210 // May be called from multiple threads.
bungeman@google.come8f05922012-08-16 16:13:40 +0000211 SkAutoMutexAcquire ama(fStreamMutex);
212
halcanary96fcdcc2015-08-27 07:41:13 -0700213 *fragmentStart = nullptr;
214 *fragmentContext = nullptr;
bungeman@google.come8f05922012-08-16 16:13:40 +0000215
bungeman0babd3c2015-02-18 11:01:05 -0800216 if (!fStream->seek(static_cast<size_t>(fileOffset))) {
bungeman@google.come8f05922012-08-16 16:13:40 +0000217 return E_FAIL;
218 }
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000219 SkAutoTMalloc<uint8_t> streamData(static_cast<size_t>(fragmentSize));
bungeman@google.come8f05922012-08-16 16:13:40 +0000220 if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) {
221 return E_FAIL;
222 }
223
224 *fragmentStart = streamData.get();
mtklein18300a32016-03-16 13:53:35 -0700225 *fragmentContext = streamData.release();
bungeman@google.come8f05922012-08-16 16:13:40 +0000226 }
227 return S_OK;
228}
229
230void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) {
bungeman@google.com6cab1a42013-05-29 13:43:31 +0000231 sk_free(fragmentContext);
bungeman@google.come8f05922012-08-16 16:13:40 +0000232}
233
234HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) {
235 *fileSize = fStream->getLength();
236 return S_OK;
237}
238
239HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetLastWriteTime(UINT64* lastWriteTime) {
240 // The concept of last write time does not apply to this loader.
241 *lastWriteTime = 0;
242 return E_NOTIMPL;
243}
mtklein1ee76512015-11-02 10:20:27 -0800244
245#endif//defined(SK_BUILD_FOR_WIN32)