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