• 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 #include "include/core/SkTypes.h"
8 #if defined(SK_BUILD_FOR_WIN)
9 
10 #include "include/core/SkTypes.h"
11 #include "include/private/SkTFitsIn.h"
12 #include "include/private/SkTemplates.h"
13 #include "src/utils/win/SkDWriteFontFileStream.h"
14 #include "src/utils/win/SkHRESULT.h"
15 #include "src/utils/win/SkTScopedComPtr.h"
16 
17 #include <dwrite.h>
18 
19 ///////////////////////////////////////////////////////////////////////////////
20 //  SkIDWriteFontFileStream
21 
SkDWriteFontFileStream(IDWriteFontFileStream * fontFileStream)22 SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream)
23     : fFontFileStream(SkRefComPtr(fontFileStream))
24     , fPos(0)
25     , fLockedMemory(nullptr)
26     , fFragmentLock(nullptr) {
27 }
28 
~SkDWriteFontFileStream()29 SkDWriteFontFileStream::~SkDWriteFontFileStream() {
30     if (fFragmentLock) {
31         fFontFileStream->ReleaseFileFragment(fFragmentLock);
32     }
33 }
34 
read(void * buffer,size_t size)35 size_t SkDWriteFontFileStream::read(void* buffer, size_t size) {
36     HRESULT hr = S_OK;
37 
38     if (nullptr == buffer) {
39         size_t fileSize = this->getLength();
40 
41         if (fPos + size > fileSize) {
42             size_t skipped = fileSize - fPos;
43             fPos = fileSize;
44             return skipped;
45         } else {
46             fPos += size;
47             return size;
48         }
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.
62     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 
isAtEnd() const80 bool SkDWriteFontFileStream::isAtEnd() const {
81     return fPos == this->getLength();
82 }
83 
rewind()84 bool SkDWriteFontFileStream::rewind() {
85     fPos = 0;
86     return true;
87 }
88 
onDuplicate() const89 SkDWriteFontFileStream* SkDWriteFontFileStream::onDuplicate() const {
90     return new SkDWriteFontFileStream(fFontFileStream.get());
91 }
92 
getPosition() const93 size_t SkDWriteFontFileStream::getPosition() const {
94     return fPos;
95 }
96 
seek(size_t position)97 bool SkDWriteFontFileStream::seek(size_t position) {
98     size_t length = this->getLength();
99     fPos = (position > length) ? length : position;
100     return true;
101 }
102 
move(long offset)103 bool SkDWriteFontFileStream::move(long offset) {
104     return seek(fPos + offset);
105 }
106 
onFork() const107 SkDWriteFontFileStream* SkDWriteFontFileStream::onFork() const {
108     std::unique_ptr<SkDWriteFontFileStream> that(this->duplicate());
109     that->seek(fPos);
110     return that.release();
111 }
112 
getLength() const113 size_t SkDWriteFontFileStream::getLength() const {
114     UINT64 realFileSize = 0;
115     fFontFileStream->GetFileSize(&realFileSize);
116     if (!SkTFitsIn<size_t>(realFileSize)) {
117         return 0;
118     }
119     return static_cast<size_t>(realFileSize);
120 }
121 
getMemoryBase()122 const void* SkDWriteFontFileStream::getMemoryBase() {
123     if (fLockedMemory) {
124         return fLockedMemory;
125     }
126 
127     UINT64 fileSize;
128     HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size");
129     HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock),
130          "Could not lock file fragment.");
131     return fLockedMemory;
132 }
133 
134 ///////////////////////////////////////////////////////////////////////////////
135 //  SkIDWriteFontFileStreamWrapper
136 
Create(SkStreamAsset * stream,SkDWriteFontFileStreamWrapper ** streamFontFileStream)137 HRESULT SkDWriteFontFileStreamWrapper::Create(SkStreamAsset* stream,
138                                               SkDWriteFontFileStreamWrapper** streamFontFileStream)
139 {
140     *streamFontFileStream = new SkDWriteFontFileStreamWrapper(stream);
141     if (nullptr == *streamFontFileStream) {
142         return E_OUTOFMEMORY;
143     }
144     return S_OK;
145 }
146 
SkDWriteFontFileStreamWrapper(SkStreamAsset * stream)147 SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStreamAsset* stream)
148     : fRefCount(1), fStream(stream) {
149 }
150 
QueryInterface(REFIID iid,void ** ppvObject)151 SK_STDMETHODIMP SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) {
152     if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
153         *ppvObject = this;
154         AddRef();
155         return S_OK;
156     } else {
157         *ppvObject = nullptr;
158         return E_NOINTERFACE;
159     }
160 }
161 
SK_STDMETHODIMP_(ULONG)162 SK_STDMETHODIMP_(ULONG) SkDWriteFontFileStreamWrapper::AddRef() {
163     return InterlockedIncrement(&fRefCount);
164 }
165 
SK_STDMETHODIMP_(ULONG)166 SK_STDMETHODIMP_(ULONG) SkDWriteFontFileStreamWrapper::Release() {
167     ULONG newCount = InterlockedDecrement(&fRefCount);
168     if (0 == newCount) {
169         delete this;
170     }
171     return newCount;
172 }
173 
ReadFileFragment(void const ** fragmentStart,UINT64 fileOffset,UINT64 fragmentSize,void ** fragmentContext)174 SK_STDMETHODIMP SkDWriteFontFileStreamWrapper::ReadFileFragment(
175     void const** fragmentStart,
176     UINT64 fileOffset,
177     UINT64 fragmentSize,
178     void** fragmentContext)
179 {
180     // The loader is responsible for doing a bounds check.
181     UINT64 fileSize;
182     this->GetFileSize(&fileSize);
183     if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) {
184         *fragmentStart = nullptr;
185         *fragmentContext = nullptr;
186         return E_FAIL;
187     }
188 
189     if (!SkTFitsIn<size_t>(fileOffset + fragmentSize)) {
190         return E_FAIL;
191     }
192 
193     const void* data = fStream->getMemoryBase();
194     if (data) {
195         *fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(fileOffset);
196         *fragmentContext = nullptr;
197 
198     } else {
199         // May be called from multiple threads.
200         SkAutoMutexExclusive ama(fStreamMutex);
201 
202         *fragmentStart = nullptr;
203         *fragmentContext = nullptr;
204 
205         if (!fStream->seek(static_cast<size_t>(fileOffset))) {
206             return E_FAIL;
207         }
208         SkAutoTMalloc<uint8_t> streamData(static_cast<size_t>(fragmentSize));
209         if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) {
210             return E_FAIL;
211         }
212 
213         *fragmentStart = streamData.get();
214         *fragmentContext = streamData.release();
215     }
216     return S_OK;
217 }
218 
SK_STDMETHODIMP_(void)219 SK_STDMETHODIMP_(void) SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) {
220     sk_free(fragmentContext);
221 }
222 
GetFileSize(UINT64 * fileSize)223 SK_STDMETHODIMP SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) {
224     *fileSize = fStream->getLength();
225     return S_OK;
226 }
227 
GetLastWriteTime(UINT64 * lastWriteTime)228 SK_STDMETHODIMP SkDWriteFontFileStreamWrapper::GetLastWriteTime(UINT64* lastWriteTime) {
229     // The concept of last write time does not apply to this loader.
230     *lastWriteTime = 0;
231     return E_NOTIMPL;
232 }
233 
234 #endif//defined(SK_BUILD_FOR_WIN)
235