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