diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/src/utils/win/SkDWriteFontFileStream.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/src/utils/win/SkDWriteFontFileStream.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,232 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkTypes.h" +#include "SkDWriteFontFileStream.h" +#include "SkHRESULT.h" +#include "SkTemplates.h" +#include "SkTFitsIn.h" +#include "SkTScopedComPtr.h" + +#include + +/////////////////////////////////////////////////////////////////////////////// +// SkIDWriteFontFileStream + +SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream) + : fFontFileStream(SkRefComPtr(fontFileStream)) + , fPos(0) + , fLockedMemory(NULL) + , fFragmentLock(NULL) { +} + +SkDWriteFontFileStream::~SkDWriteFontFileStream() { + if (fFragmentLock) { + fFontFileStream->ReleaseFileFragment(fFragmentLock); + } +} + +size_t SkDWriteFontFileStream::read(void* buffer, size_t size) { + HRESULT hr = S_OK; + + if (NULL == buffer) { + size_t fileSize = this->getLength(); + + if (fPos + size > fileSize) { + size_t skipped = fileSize - fPos; + fPos = fileSize; + return skipped; + } else { + fPos += size; + return size; + } + } + + const void* start; + void* fragmentLock; + hr = fFontFileStream->ReadFileFragment(&start, fPos, size, &fragmentLock); + if (SUCCEEDED(hr)) { + memcpy(buffer, start, size); + fFontFileStream->ReleaseFileFragment(fragmentLock); + fPos += size; + return size; + } + + //The read may have failed because we asked for too much data. + size_t fileSize = this->getLength(); + if (fPos + size <= fileSize) { + //This means we were within bounds, but failed for some other reason. + return 0; + } + + size_t read = fileSize - fPos; + hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock); + if (SUCCEEDED(hr)) { + memcpy(buffer, start, read); + fFontFileStream->ReleaseFileFragment(fragmentLock); + fPos = fileSize; + return read; + } + + return 0; +} + +bool SkDWriteFontFileStream::isAtEnd() const { + return fPos == this->getLength(); +} + +bool SkDWriteFontFileStream::rewind() { + fPos = 0; + return true; +} + +SkDWriteFontFileStream* SkDWriteFontFileStream::duplicate() const { + return SkNEW_ARGS(SkDWriteFontFileStream, (fFontFileStream.get())); +} + +size_t SkDWriteFontFileStream::getPosition() const { + return fPos; +} + +bool SkDWriteFontFileStream::seek(size_t position) { + size_t length = this->getLength(); + fPos = (position > length) ? length : position; + return true; +} + +bool SkDWriteFontFileStream::move(long offset) { + return seek(fPos + offset); +} + +SkDWriteFontFileStream* SkDWriteFontFileStream::fork() const { + SkAutoTUnref that(this->duplicate()); + that->seek(fPos); + return that.detach(); +} + +size_t SkDWriteFontFileStream::getLength() const { + HRESULT hr = S_OK; + UINT64 realFileSize = 0; + hr = fFontFileStream->GetFileSize(&realFileSize); + if (!SkTFitsIn(realFileSize)) { + return 0; + } + return static_cast(realFileSize); +} + +const void* SkDWriteFontFileStream::getMemoryBase() { + if (fLockedMemory) { + return fLockedMemory; + } + + UINT64 fileSize; + HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size"); + HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock), + "Could not lock file fragment."); + return fLockedMemory; +} + +/////////////////////////////////////////////////////////////////////////////// +// SkIDWriteFontFileStreamWrapper + +HRESULT SkDWriteFontFileStreamWrapper::Create(SkStream* stream, SkDWriteFontFileStreamWrapper** streamFontFileStream) { + *streamFontFileStream = new SkDWriteFontFileStreamWrapper(stream); + if (NULL == streamFontFileStream) { + return E_OUTOFMEMORY; + } + return S_OK; +} + +SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStream* stream) + : fRefCount(1), fStream(SkRef(stream)) { +} + +HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) { + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { + *ppvObject = this; + AddRef(); + return S_OK; + } else { + *ppvObject = NULL; + return E_NOINTERFACE; + } +} + +ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::AddRef() { + return InterlockedIncrement(&fRefCount); +} + +ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::Release() { + ULONG newCount = InterlockedDecrement(&fRefCount); + if (0 == newCount) { + delete this; + } + return newCount; +} + +HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment( + void const** fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + void** fragmentContext) +{ + // The loader is responsible for doing a bounds check. + UINT64 fileSize; + this->GetFileSize(&fileSize); + if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) { + *fragmentStart = NULL; + *fragmentContext = NULL; + return E_FAIL; + } + + if (!SkTFitsIn(fileOffset + fragmentSize)) { + return E_FAIL; + } + + const void* data = fStream->getMemoryBase(); + if (NULL != data) { + *fragmentStart = static_cast(data) + static_cast(fileOffset); + *fragmentContext = NULL; + + } else { + //May be called from multiple threads. + SkAutoMutexAcquire ama(fStreamMutex); + + *fragmentStart = NULL; + *fragmentContext = NULL; + + if (!fStream->rewind()) { + return E_FAIL; + } + if (fStream->skip(static_cast(fileOffset)) != fileOffset) { + return E_FAIL; + } + SkAutoTMalloc streamData(static_cast(fragmentSize)); + if (fStream->read(streamData.get(), static_cast(fragmentSize)) != fragmentSize) { + return E_FAIL; + } + + *fragmentStart = streamData.get(); + *fragmentContext = streamData.detach(); + } + return S_OK; +} + +void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) { + sk_free(fragmentContext); +} + +HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) { + *fileSize = fStream->getLength(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetLastWriteTime(UINT64* lastWriteTime) { + // The concept of last write time does not apply to this loader. + *lastWriteTime = 0; + return E_NOTIMPL; +}