• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "SkTypes.h"
9 #include "SkDWriteFontFileStream.h"
10 #include "SkHRESULT.h"
11 
12 #include <dwrite.h>
13 #include <limits>
14 
15 ///////////////////////////////////////////////////////////////////////////////
16 //  SkIDWriteFontFileStream
17 
SkDWriteFontFileStream(IDWriteFontFileStream * fontFileStream)18 SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream)
19     : fFontFileStream(fontFileStream)
20     , fPos(0)
21     , fLockedMemory(NULL)
22     , fFragmentLock(NULL) {
23     fontFileStream->AddRef();
24 }
25 
~SkDWriteFontFileStream()26 SkDWriteFontFileStream::~SkDWriteFontFileStream() {
27     if (fFragmentLock) {
28         fFontFileStream->ReleaseFileFragment(fFragmentLock);
29     }
30 }
31 
getMemoryBase()32 const void* SkDWriteFontFileStream::getMemoryBase() {
33     if (fLockedMemory) {
34         return fLockedMemory;
35     }
36 
37     UINT64 fileSize;
38     HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size");
39     HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock),
40          "Could not lock file fragment.");
41     return fLockedMemory;
42 }
43 
rewind()44 bool SkDWriteFontFileStream::rewind() {
45     fPos = 0;
46     return true;
47 }
48 
read(void * buffer,size_t size)49 size_t SkDWriteFontFileStream::read(void* buffer, size_t size) {
50     HRESULT hr = S_OK;
51 
52     if (NULL == buffer) {
53         UINT64 realFileSize = 0;
54         hr = fFontFileStream->GetFileSize(&realFileSize);
55         if (realFileSize > (std::numeric_limits<size_t>::max)()) {
56             return 0;
57         }
58         size_t fileSize = static_cast<size_t>(realFileSize);
59         if (size == 0) {
60             return fileSize;
61         } else {
62             if (fPos + size > fileSize) {
63                 size_t skipped = fileSize - fPos;
64                 fPos = fileSize;
65                 return skipped;
66             } else {
67                 fPos += size;
68                 return size;
69             }
70         }
71     }
72 
73     const void* start;
74     void* fragmentLock;
75     hr = fFontFileStream->ReadFileFragment(&start, fPos, size, &fragmentLock);
76     if (SUCCEEDED(hr)) {
77         memcpy(buffer, start, size);
78         fFontFileStream->ReleaseFileFragment(fragmentLock);
79         fPos += size;
80         return size;
81     }
82 
83     //The read may have failed because we asked for too much data.
84     UINT64 realFileSize = 0;
85     hr = fFontFileStream->GetFileSize(&realFileSize);
86     if (realFileSize > (std::numeric_limits<size_t>::max)()) {
87         return 0;
88     }
89     size_t fileSize = static_cast<size_t>(realFileSize);
90     if (fPos + size > fileSize) {
91         size_t read = fileSize - fPos;
92         hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock);
93         if (SUCCEEDED(hr)) {
94             memcpy(buffer, start, read);
95             fFontFileStream->ReleaseFileFragment(fragmentLock);
96             fPos = fileSize;
97             return read;
98         }
99         return 0;
100     } else {
101         //This means we were within bounds, but failed for some other reason.
102         return 0;
103     }
104 }
105 
106 
107 ///////////////////////////////////////////////////////////////////////////////
108 //  SkIDWriteFontFileStreamWrapper
109 
Create(SkStream * stream,SkDWriteFontFileStreamWrapper ** streamFontFileStream)110 HRESULT SkDWriteFontFileStreamWrapper::Create(SkStream* stream, SkDWriteFontFileStreamWrapper** streamFontFileStream) {
111     *streamFontFileStream = new SkDWriteFontFileStreamWrapper(stream);
112     if (NULL == streamFontFileStream) {
113         return E_OUTOFMEMORY;
114     }
115     return S_OK;
116 }
117 
SkDWriteFontFileStreamWrapper(SkStream * stream)118 SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStream* stream)
119     : fRefCount(1), fStream(stream) {
120     stream->ref();
121 }
122 
QueryInterface(REFIID iid,void ** ppvObject)123 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) {
124     if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
125         *ppvObject = this;
126         AddRef();
127         return S_OK;
128     } else {
129         *ppvObject = NULL;
130         return E_NOINTERFACE;
131     }
132 }
133 
AddRef()134 ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::AddRef() {
135     return InterlockedIncrement(&fRefCount);
136 }
137 
Release()138 ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::Release() {
139     ULONG newCount = InterlockedDecrement(&fRefCount);
140     if (0 == newCount) {
141         delete this;
142     }
143     return newCount;
144 }
145 
ReadFileFragment(void const ** fragmentStart,UINT64 fileOffset,UINT64 fragmentSize,void ** fragmentContext)146 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment(
147     void const** fragmentStart,
148     UINT64 fileOffset,
149     UINT64 fragmentSize,
150     void** fragmentContext)
151 {
152     // The loader is responsible for doing a bounds check.
153     UINT64 fileSize;
154     this->GetFileSize(&fileSize);
155     if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) {
156         *fragmentStart = NULL;
157         *fragmentContext = NULL;
158         return E_FAIL;
159     }
160 
161     if (fileOffset + fragmentSize > (std::numeric_limits<size_t>::max)()) {
162         return E_FAIL;
163     }
164 
165     const void* data = fStream->getMemoryBase();
166     if (NULL != data) {
167         *fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(fileOffset);
168         *fragmentContext = NULL;
169 
170     } else {
171         //May be called from multiple threads.
172         SkAutoMutexAcquire ama(fStreamMutex);
173 
174         *fragmentStart = NULL;
175         *fragmentContext = NULL;
176 
177         if (!fStream->rewind()) {
178             return E_FAIL;
179         }
180         if (fStream->skip(static_cast<size_t>(fileOffset)) != fileOffset) {
181             return E_FAIL;
182         }
183         SkAutoTDeleteArray<uint8_t> streamData(new uint8_t[static_cast<size_t>(fragmentSize)]);
184         if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) {
185             return E_FAIL;
186         }
187 
188         *fragmentStart = streamData.get();
189         *fragmentContext = streamData.detach();
190     }
191     return S_OK;
192 }
193 
ReleaseFileFragment(void * fragmentContext)194 void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) {
195     if (NULL == fragmentContext) {
196         return;
197     }
198     delete [] fragmentContext;
199 }
200 
GetFileSize(UINT64 * fileSize)201 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) {
202     *fileSize = fStream->getLength();
203     return S_OK;
204 }
205 
GetLastWriteTime(UINT64 * lastWriteTime)206 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetLastWriteTime(UINT64* lastWriteTime) {
207     // The concept of last write time does not apply to this loader.
208     *lastWriteTime = 0;
209     return E_NOTIMPL;
210 }
211