DirectWrite font host for skia.
https://codereview.appspot.com/5417063/ git-svn-id: http://skia.googlecode.com/svn/trunk@5128 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
0557d9ea94
commit
e8f0592ae8
@ -50,6 +50,11 @@
|
||||
],
|
||||
}
|
||||
],
|
||||
[ 'skia_directwrite', {
|
||||
'defines': [
|
||||
'SK_FONTHOST_WIN_DW',
|
||||
],
|
||||
}],
|
||||
[ 'skia_mesa', {
|
||||
'defines': [
|
||||
'SK_MESA',
|
||||
|
@ -70,6 +70,7 @@
|
||||
# Do not turn on 'skia_angle' - it is currently experimental
|
||||
'skia_angle%': 0,
|
||||
'skia_arch_type%': 'x86',
|
||||
'skia_directwrite%': 0,
|
||||
'android_make_apk%': 1,
|
||||
'skia_gpu%': 1,
|
||||
'skia_static_initializers%': 1,
|
||||
@ -85,6 +86,7 @@
|
||||
'skia_angle%': '<(skia_angle)',
|
||||
'skia_arch_type%': '<(skia_arch_type)',
|
||||
'skia_arch_width%': '<(skia_arch_width)',
|
||||
'skia_directwrite%': '<(skia_directwrite)',
|
||||
'android_make_apk%': '<(android_make_apk)',
|
||||
'skia_gpu%': '<(skia_gpu)',
|
||||
'skia_static_initializers%': '<(skia_static_initializers)',
|
||||
@ -99,4 +101,4 @@
|
||||
# tab-width:2
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=2 shiftwidth=2:
|
||||
# vim: set expandtab tabstop=2 shiftwidth=2:
|
@ -24,6 +24,7 @@
|
||||
'../src/ports/SkFontDescriptor.cpp',
|
||||
'../src/ports/SkFontHost_sandbox_none.cpp',
|
||||
'../src/ports/SkFontHost_win.cpp',
|
||||
'../src/ports/SkFontHost_win_dw.cpp',
|
||||
'../src/ports/SkGlobalInitialization_default.cpp',
|
||||
'../src/ports/SkThread_win.cpp',
|
||||
|
||||
@ -70,6 +71,18 @@
|
||||
[ 'skia_os == "win"', {
|
||||
'include_dirs': [
|
||||
'config/win',
|
||||
'../src/utils/win',
|
||||
],
|
||||
'conditions': [
|
||||
[ 'skia_directwrite', {
|
||||
'sources!': [
|
||||
'../src/ports/SkFontHost_win.cpp',
|
||||
],
|
||||
}, { # else !skia_directwrite
|
||||
'sources!': [
|
||||
'../src/ports/SkFontHost_win_dw.cpp',
|
||||
],
|
||||
}],
|
||||
],
|
||||
'sources!': [ # these are used everywhere but windows
|
||||
'../src/ports/SkDebug_stdio.cpp',
|
||||
|
@ -2,10 +2,11 @@
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'utils',
|
||||
'dependencies': [
|
||||
'core.gyp:core',
|
||||
],
|
||||
'type': 'static_library',
|
||||
'include_dirs': [
|
||||
'../include/config',
|
||||
'../include/core',
|
||||
'../include/effects',
|
||||
'../include/pipe',
|
||||
'../include/utils',
|
||||
@ -13,6 +14,7 @@
|
||||
'../include/utils/unix',
|
||||
'../include/utils/win',
|
||||
'../include/xml',
|
||||
'../src/utils',
|
||||
],
|
||||
'sources': [
|
||||
'../include/utils/SkBoundaryPatch.h',
|
||||
@ -45,6 +47,7 @@
|
||||
'../src/utils/SkCullPoints.cpp',
|
||||
'../src/utils/SkDeferredCanvas.cpp',
|
||||
'../src/utils/SkDumpCanvas.cpp',
|
||||
'../src/utils/SkFloatUtils.h',
|
||||
'../src/utils/SkInterpolator.cpp',
|
||||
'../src/utils/SkLayer.cpp',
|
||||
'../src/utils/SkMatrix44.cpp',
|
||||
@ -77,6 +80,10 @@
|
||||
'../include/utils/win/SkIStream.h',
|
||||
'../include/utils/win/SkTScopedComPtr.h',
|
||||
'../src/utils/win/SkAutoCoInitialize.cpp',
|
||||
'../src/utils/win/SkDWriteFontFileStream.cpp',
|
||||
'../src/utils/win/SkDWriteFontFileStream.h',
|
||||
'../src/utils/win/SkDWriteGeometrySink.cpp',
|
||||
'../src/utils/win/SkDWriteGeometrySink.h',
|
||||
'../src/utils/win/SkHRESULT.cpp',
|
||||
'../src/utils/win/SkIStream.cpp',
|
||||
'../src/utils/win/SkWGL_win.cpp',
|
||||
@ -149,6 +156,10 @@
|
||||
'../include/utils/win/SkIStream.h',
|
||||
'../include/utils/win/SkTScopedComPtr.h',
|
||||
'../src/utils/win/SkAutoCoInitialize.cpp',
|
||||
'../src/utils/win/SkDWriteFontFileStream.cpp',
|
||||
'../src/utils/win/SkDWriteFontFileStream.h',
|
||||
'../src/utils/win/SkDWriteGeometrySink.cpp',
|
||||
'../src/utils/win/SkDWriteGeometrySink.h',
|
||||
'../src/utils/win/SkHRESULT.cpp',
|
||||
'../src/utils/win/SkIStream.cpp',
|
||||
],
|
||||
|
@ -36,6 +36,7 @@ If the HRESULT FAILED then the macro will return from the current function.
|
||||
In variants ending with 'M' the given message will be traced when FAILED.
|
||||
The HR variants will return the HRESULT when FAILED.
|
||||
The HRB variants will return false when FAILED.
|
||||
The HRN variants will return NULL when FAILED.
|
||||
The HRV variants will simply return when FAILED.
|
||||
*/
|
||||
#define HR(ex) HR_GENERAL(ex, NULL, _hr)
|
||||
@ -44,6 +45,9 @@ The HRV variants will simply return when FAILED.
|
||||
#define HRB(ex) HR_GENERAL(ex, NULL, false)
|
||||
#define HRBM(ex, msg) HR_GENERAL(ex, msg, false)
|
||||
|
||||
#define HRN(ex) HR_GENERAL(ex, NULL, NULL)
|
||||
#define HRNM(ex, msg) HR_GENERAL(ex, msg, NULL)
|
||||
|
||||
#define HRV(ex) HR_GENERAL(ex, NULL, )
|
||||
#define HRVM(ex, msg) HR_GENERAL(ex, msg, )
|
||||
//@}
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
~SkTScopedComPtr() {
|
||||
this->reset();
|
||||
}
|
||||
T &operator*() const { return *fPtr; }
|
||||
T &operator*() const { SkASSERT(fPtr != NULL); return *fPtr; }
|
||||
SkBlockComRef<T> *operator->() const {
|
||||
return static_cast<SkBlockComRef<T>*>(fPtr);
|
||||
}
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
extern void skia_set_text_gamma(float blackGamma, float whiteGamma);
|
||||
|
||||
#ifdef SK_BUILD_FOR_WIN
|
||||
#if defined(SK_BUILD_FOR_WIN) && !defined(SK_FONTHOST_WIN_DW)
|
||||
extern SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&);
|
||||
#endif
|
||||
|
||||
@ -45,7 +45,7 @@ static const char gText[] =
|
||||
class TextBoxView : public SampleView {
|
||||
public:
|
||||
TextBoxView() {
|
||||
#ifdef SK_BUILD_FOR_WIN
|
||||
#if defined(SK_BUILD_FOR_WIN) && !defined(SK_FONTHOST_WIN_DW)
|
||||
LOGFONT lf;
|
||||
sk_bzero(&lf, sizeof(lf));
|
||||
lf.lfHeight = 9;
|
||||
|
@ -12,6 +12,10 @@
|
||||
|
||||
SK_DEFINE_INST_COUNT(SkAdvancedTypefaceMetrics)
|
||||
|
||||
#if defined(SK_BUILD_FOR_WIN) && defined(SK_FONTHOST_WIN_DW)
|
||||
#include <DWrite.h>
|
||||
#endif
|
||||
|
||||
#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
@ -253,13 +257,20 @@ SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData(
|
||||
|
||||
// Make AdvanceMetric template functions available for linking with typename
|
||||
// WidthRange and VerticalAdvanceRange.
|
||||
#if defined(SK_BUILD_FOR_WIN)
|
||||
#if defined(SK_BUILD_FOR_WIN) && !defined(SK_FONTHOST_WIN_DW)
|
||||
template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
|
||||
HDC hdc,
|
||||
int num_glyphs,
|
||||
const uint32_t* subsetGlyphIDs,
|
||||
uint32_t subsetGlyphIDsLength,
|
||||
bool (*getAdvance)(HDC hdc, int gId, int16_t* data));
|
||||
#elif defined(SK_BUILD_FOR_WIN) && defined(SK_FONTHOST_WIN_DW)
|
||||
template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
|
||||
IDWriteFontFace* fontFace,
|
||||
int num_glyphs,
|
||||
const uint32_t* subsetGlyphIDs,
|
||||
uint32_t subsetGlyphIDsLength,
|
||||
bool (*getAdvance)(IDWriteFontFace* fontFace, int gId, int16_t* data));
|
||||
#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
|
||||
template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
|
||||
FT_Face face,
|
||||
|
1519
src/ports/SkFontHost_win_dw.cpp
Normal file
1519
src/ports/SkFontHost_win_dw.cpp
Normal file
File diff suppressed because it is too large
Load Diff
173
src/utils/SkFloatUtils.h
Normal file
173
src/utils/SkFloatUtils.h
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkFloatUtils_DEFINED
|
||||
#define SkFloatUtils_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
|
||||
template <size_t size>
|
||||
class SkTypeWithSize {
|
||||
public:
|
||||
// Prevents using SkTypeWithSize<N> with non-specialized N.
|
||||
typedef void UInt;
|
||||
};
|
||||
|
||||
template <>
|
||||
class SkTypeWithSize<32> {
|
||||
public:
|
||||
typedef uint32_t UInt;
|
||||
};
|
||||
|
||||
template <>
|
||||
class SkTypeWithSize<64> {
|
||||
public:
|
||||
typedef uint64_t UInt;
|
||||
};
|
||||
|
||||
template <typename RawType>
|
||||
struct SkNumericLimits {
|
||||
static const int digits = 0;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct SkNumericLimits<double> {
|
||||
static const int digits = DBL_MANT_DIG;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct SkNumericLimits<float> {
|
||||
static const int digits = FLT_MANT_DIG;
|
||||
};
|
||||
|
||||
//See
|
||||
//http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison/3423299#3423299
|
||||
//http://code.google.com/p/googletest/source/browse/trunk/include/gtest/internal/gtest-internal.h
|
||||
//http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
|
||||
|
||||
template <typename RawType, unsigned int ULPs>
|
||||
class SkFloatingPoint {
|
||||
public:
|
||||
/** Bits is a unsigned integer the same size as the floating point number. */
|
||||
typedef typename SkTypeWithSize<sizeof(RawType) * CHAR_BIT>::UInt Bits;
|
||||
|
||||
/** # of bits in a number. */
|
||||
static const size_t kBitCount = CHAR_BIT * sizeof(RawType);
|
||||
|
||||
/** # of fraction bits in a number. */
|
||||
static const size_t kFractionBitCount = SkNumericLimits<RawType>::digits - 1;
|
||||
|
||||
/** # of exponent bits in a number. */
|
||||
static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
|
||||
|
||||
/** The mask for the sign bit. */
|
||||
static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
|
||||
|
||||
/** The mask for the fraction bits. */
|
||||
static const Bits kFractionBitMask =
|
||||
~static_cast<Bits>(0) >> (kExponentBitCount + 1);
|
||||
|
||||
/** The mask for the exponent bits. */
|
||||
static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
|
||||
|
||||
/** How many ULP's (Units in the Last Place) to tolerate when comparing. */
|
||||
static const size_t kMaxUlps = ULPs;
|
||||
|
||||
/**
|
||||
* Constructs a FloatingPoint from a raw floating-point number.
|
||||
*
|
||||
* On an Intel CPU, passing a non-normalized NAN (Not a Number)
|
||||
* around may change its bits, although the new value is guaranteed
|
||||
* to be also a NAN. Therefore, don't expect this constructor to
|
||||
* preserve the bits in x when x is a NAN.
|
||||
*/
|
||||
explicit SkFloatingPoint(const RawType& x) { fU.value = x; }
|
||||
|
||||
/** Returns the exponent bits of this number. */
|
||||
Bits exponent_bits() const { return kExponentBitMask & fU.bits; }
|
||||
|
||||
/** Returns the fraction bits of this number. */
|
||||
Bits fraction_bits() const { return kFractionBitMask & fU.bits; }
|
||||
|
||||
/** Returns true iff this is NAN (not a number). */
|
||||
bool is_nan() const {
|
||||
// It's a NAN if both of the folloowing are true:
|
||||
// * the exponent bits are all ones
|
||||
// * the fraction bits are not all zero.
|
||||
return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff this number is at most kMaxUlps ULP's away from ths.
|
||||
* In particular, this function:
|
||||
* - returns false if either number is (or both are) NAN.
|
||||
* - treats really large numbers as almost equal to infinity.
|
||||
* - thinks +0.0 and -0.0 are 0 DLP's apart.
|
||||
*/
|
||||
bool AlmostEquals(const SkFloatingPoint& rhs) const {
|
||||
// Any comparison operation involving a NAN must return false.
|
||||
if (is_nan() || rhs.is_nan()) return false;
|
||||
|
||||
const Bits dist = DistanceBetweenSignAndMagnitudeNumbers(fU.bits,
|
||||
rhs.fU.bits);
|
||||
//SkDEBUGF(("(%f, %f, %d) ", u_.value_, rhs.u_.value_, dist));
|
||||
return dist <= kMaxUlps;
|
||||
}
|
||||
|
||||
private:
|
||||
/** The data type used to store the actual floating-point number. */
|
||||
union FloatingPointUnion {
|
||||
/** The raw floating-point number. */
|
||||
RawType value;
|
||||
/** The bits that represent the number. */
|
||||
Bits bits;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts an integer from the sign-and-magnitude representation to
|
||||
* the biased representation. More precisely, let N be 2 to the
|
||||
* power of (kBitCount - 1), an integer x is represented by the
|
||||
* unsigned number x + N.
|
||||
*
|
||||
* For instance,
|
||||
*
|
||||
* -N + 1 (the most negative number representable using
|
||||
* sign-and-magnitude) is represented by 1;
|
||||
* 0 is represented by N; and
|
||||
* N - 1 (the biggest number representable using
|
||||
* sign-and-magnitude) is represented by 2N - 1.
|
||||
*
|
||||
* Read http://en.wikipedia.org/wiki/Signed_number_representations
|
||||
* for more details on signed number representations.
|
||||
*/
|
||||
static Bits SignAndMagnitudeToBiased(const Bits &sam) {
|
||||
if (kSignBitMask & sam) {
|
||||
// sam represents a negative number.
|
||||
return ~sam + 1;
|
||||
} else {
|
||||
// sam represents a positive number.
|
||||
return kSignBitMask | sam;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given two numbers in the sign-and-magnitude representation,
|
||||
* returns the distance between them as an unsigned number.
|
||||
*/
|
||||
static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
|
||||
const Bits &sam2) {
|
||||
const Bits biased1 = SignAndMagnitudeToBiased(sam1);
|
||||
const Bits biased2 = SignAndMagnitudeToBiased(sam2);
|
||||
return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
|
||||
}
|
||||
|
||||
FloatingPointUnion fU;
|
||||
};
|
||||
|
||||
#endif
|
210
src/utils/win/SkDWriteFontFileStream.cpp
Normal file
210
src/utils/win/SkDWriteFontFileStream.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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 <dwrite.h>
|
||||
#include <limits>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SkIDWriteFontFileStream
|
||||
|
||||
SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream)
|
||||
: fFontFileStream(fontFileStream)
|
||||
, fPos(0)
|
||||
, fLockedMemory(NULL)
|
||||
, fFragmentLock(NULL) {
|
||||
fontFileStream->AddRef();
|
||||
}
|
||||
|
||||
SkDWriteFontFileStream::~SkDWriteFontFileStream() {
|
||||
if (fFragmentLock) {
|
||||
fFontFileStream->ReleaseFileFragment(fFragmentLock);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool SkDWriteFontFileStream::rewind() {
|
||||
fPos = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t SkDWriteFontFileStream::read(void* buffer, size_t size) {
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (NULL == buffer) {
|
||||
UINT64 realFileSize = 0;
|
||||
hr = fFontFileStream->GetFileSize(&realFileSize);
|
||||
if (realFileSize > (std::numeric_limits<size_t>::max)()) {
|
||||
return 0;
|
||||
}
|
||||
size_t fileSize = static_cast<size_t>(realFileSize);
|
||||
if (size == 0) {
|
||||
return fileSize;
|
||||
} else {
|
||||
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.
|
||||
UINT64 realFileSize = 0;
|
||||
hr = fFontFileStream->GetFileSize(&realFileSize);
|
||||
if (realFileSize > (std::numeric_limits<size_t>::max)()) {
|
||||
return 0;
|
||||
}
|
||||
size_t fileSize = static_cast<size_t>(realFileSize);
|
||||
if (fPos + size > fileSize) {
|
||||
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;
|
||||
} else {
|
||||
//This means we were within bounds, but failed for some other reason.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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(stream) {
|
||||
stream->ref();
|
||||
}
|
||||
|
||||
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 (fileOffset + fragmentSize > (std::numeric_limits<size_t>::max)()) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
const void* data = fStream->getMemoryBase();
|
||||
if (NULL != data) {
|
||||
*fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(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<size_t>(fileOffset)) != fileOffset) {
|
||||
return E_FAIL;
|
||||
}
|
||||
SkAutoTDeleteArray<uint8_t> streamData(new uint8_t[static_cast<size_t>(fragmentSize)]);
|
||||
if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
*fragmentStart = streamData.get();
|
||||
*fragmentContext = streamData.detach();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) {
|
||||
if (NULL == fragmentContext) {
|
||||
return;
|
||||
}
|
||||
delete [] 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;
|
||||
}
|
69
src/utils/win/SkDWriteFontFileStream.h
Normal file
69
src/utils/win/SkDWriteFontFileStream.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkDWriteFontFileStream_DEFINED
|
||||
#define SkDWriteFontFileStream_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
|
||||
#include "SkStream.h"
|
||||
#include "SkTScopedComPtr.h"
|
||||
|
||||
#include <dwrite.h>
|
||||
|
||||
/**
|
||||
* An SkStream backed by an IDWriteFontFileStream.
|
||||
* This allows Skia code to read an IDWriteFontFileStream.
|
||||
*/
|
||||
class SkDWriteFontFileStream : public SkStream {
|
||||
public:
|
||||
explicit SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream);
|
||||
virtual ~SkDWriteFontFileStream();
|
||||
|
||||
virtual bool rewind() SK_OVERRIDE;
|
||||
virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
|
||||
virtual const void* getMemoryBase() SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkTScopedComPtr<IDWriteFontFileStream> fFontFileStream;
|
||||
size_t fPos;
|
||||
const void* fLockedMemory;
|
||||
void* fFragmentLock;
|
||||
};
|
||||
|
||||
/**
|
||||
* An IDWriteFontFileStream backed by an SkStream.
|
||||
* This allows DirectWrite to read an SkStream.
|
||||
*/
|
||||
class SkDWriteFontFileStreamWrapper : public IDWriteFontFileStream {
|
||||
public:
|
||||
// IUnknown methods
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef();
|
||||
virtual ULONG STDMETHODCALLTYPE Release();
|
||||
|
||||
// IDWriteFontFileStream methods
|
||||
virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(
|
||||
void const** fragmentStart,
|
||||
UINT64 fileOffset,
|
||||
UINT64 fragmentSize,
|
||||
void** fragmentContext);
|
||||
|
||||
virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext);
|
||||
virtual HRESULT STDMETHODCALLTYPE GetFileSize(UINT64* fileSize);
|
||||
virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(UINT64* lastWriteTime);
|
||||
|
||||
static HRESULT Create(SkStream* stream, SkDWriteFontFileStreamWrapper** streamFontFileStream);
|
||||
|
||||
private:
|
||||
explicit SkDWriteFontFileStreamWrapper(SkStream* stream);
|
||||
|
||||
ULONG fRefCount;
|
||||
SkAutoTUnref<SkStream> fStream;
|
||||
SkMutex fStreamMutex;
|
||||
};
|
||||
#endif
|
146
src/utils/win/SkDWriteGeometrySink.cpp
Normal file
146
src/utils/win/SkDWriteGeometrySink.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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 "SkDWriteGeometrySink.h"
|
||||
#include "SkFloatUtils.h"
|
||||
#include "SkPath.h"
|
||||
|
||||
#include <dwrite.h>
|
||||
#include <d2d1.h>
|
||||
|
||||
SkDWriteGeometrySink::SkDWriteGeometrySink(SkPath* path) : fRefCount(1), fPath(path) { }
|
||||
|
||||
SkDWriteGeometrySink::~SkDWriteGeometrySink() { }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SkDWriteGeometrySink::QueryInterface(REFIID iid, void **object) {
|
||||
if (NULL == object) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
if (iid == __uuidof(IUnknown) || iid == __uuidof(IDWriteGeometrySink)) {
|
||||
*object = static_cast<IDWriteGeometrySink*>(this);
|
||||
this->AddRef();
|
||||
return S_OK;
|
||||
} else {
|
||||
*object = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE SkDWriteGeometrySink::AddRef(void) {
|
||||
return static_cast<ULONG>(InterlockedIncrement(&fRefCount));
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE SkDWriteGeometrySink::Release(void) {
|
||||
ULONG res = static_cast<ULONG>(InterlockedDecrement(&fRefCount));
|
||||
if (0 == res) {
|
||||
delete this;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SkDWriteGeometrySink::SetFillMode(D2D1_FILL_MODE fillMode) {
|
||||
switch (fillMode) {
|
||||
case D2D1_FILL_MODE_ALTERNATE:
|
||||
fPath->setFillType(SkPath::kEvenOdd_FillType);
|
||||
break;
|
||||
case D2D1_FILL_MODE_WINDING:
|
||||
fPath->setFillType(SkPath::kWinding_FillType);
|
||||
break;
|
||||
default:
|
||||
SkASSERT(!"Unknown D2D1_FILL_MODE.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SkDWriteGeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT vertexFlags) {
|
||||
if (vertexFlags == D2D1_PATH_SEGMENT_NONE || vertexFlags == D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN) {
|
||||
SkASSERT(!"Invalid D2D1_PATH_SEGMENT value.");
|
||||
}
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SkDWriteGeometrySink::BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin) {
|
||||
fPath->moveTo(SkFloatToScalar(startPoint.x), SkFloatToScalar(startPoint.y));
|
||||
if (figureBegin == D2D1_FIGURE_BEGIN_HOLLOW) {
|
||||
SkASSERT(!"Invalid D2D1_FIGURE_BEGIN value.");
|
||||
}
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SkDWriteGeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount) {
|
||||
for (const D2D1_POINT_2F *end = &points[pointsCount]; points < end; ++points) {
|
||||
fPath->lineTo(SkFloatToScalar(points->x), SkFloatToScalar(points->y));
|
||||
}
|
||||
}
|
||||
|
||||
static bool approximately_equal(float a, float b) {
|
||||
const SkFloatingPoint<float, 10> lhs(a), rhs(b);
|
||||
return lhs.AlmostEquals(rhs);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
float x;
|
||||
float y;
|
||||
} Cubic[4], Quadratic[3];
|
||||
|
||||
static bool check_quadratic(const Cubic& cubic, Quadratic& reduction) {
|
||||
float dx10 = cubic[1].x - cubic[0].x;
|
||||
float dx23 = cubic[2].x - cubic[3].x;
|
||||
float midX = cubic[0].x + dx10 * 3 / 2;
|
||||
//NOTE: !approximately_equal(midX - cubic[3].x, dx23 * 3 / 2)
|
||||
//does not work as subnormals get in between the left side and 0.
|
||||
if (!approximately_equal(midX, (dx23 * 3 / 2) + cubic[3].x)) {
|
||||
return false;
|
||||
}
|
||||
float dy10 = cubic[1].y - cubic[0].y;
|
||||
float dy23 = cubic[2].y - cubic[3].y;
|
||||
float midY = cubic[0].y + dy10 * 3 / 2;
|
||||
if (!approximately_equal(midY, (dy23 * 3 / 2) + cubic[3].y)) {
|
||||
return false;
|
||||
}
|
||||
reduction[0] = cubic[0];
|
||||
reduction[1].x = midX;
|
||||
reduction[1].y = midY;
|
||||
reduction[2] = cubic[3];
|
||||
return true;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SkDWriteGeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, UINT beziersCount) {
|
||||
SkPoint lastPt;
|
||||
fPath->getLastPt(&lastPt);
|
||||
D2D1_POINT_2F prevPt = { SkScalarToFloat(lastPt.fX), SkScalarToFloat(lastPt.fY) };
|
||||
|
||||
for (const D2D1_BEZIER_SEGMENT *end = &beziers[beziersCount]; beziers < end; ++beziers) {
|
||||
Cubic cubic = { { prevPt.x, prevPt.y },
|
||||
{ beziers->point1.x, beziers->point1.y },
|
||||
{ beziers->point2.x, beziers->point2.y },
|
||||
{ beziers->point3.x, beziers->point3.y }, };
|
||||
Quadratic quadratic;
|
||||
if (check_quadratic(cubic, quadratic)) {
|
||||
fPath->quadTo(SkFloatToScalar(quadratic[1].x), SkFloatToScalar(quadratic[1].y),
|
||||
SkFloatToScalar(quadratic[2].x), SkFloatToScalar(quadratic[2].y));
|
||||
} else {
|
||||
fPath->cubicTo(SkFloatToScalar(beziers->point1.x), SkFloatToScalar(beziers->point1.y),
|
||||
SkFloatToScalar(beziers->point2.x), SkFloatToScalar(beziers->point2.y),
|
||||
SkFloatToScalar(beziers->point3.x), SkFloatToScalar(beziers->point3.y));
|
||||
}
|
||||
prevPt = beziers->point3;
|
||||
}
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE SkDWriteGeometrySink::EndFigure(D2D1_FIGURE_END figureEnd) {
|
||||
fPath->close();
|
||||
}
|
||||
|
||||
HRESULT SkDWriteGeometrySink::Close() {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT SkDWriteGeometrySink::Create(SkPath* path, IDWriteGeometrySink** geometryToPath) {
|
||||
*geometryToPath = new SkDWriteGeometrySink(path);
|
||||
return S_OK;
|
||||
}
|
46
src/utils/win/SkDWriteGeometrySink.h
Normal file
46
src/utils/win/SkDWriteGeometrySink.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkDWriteToPath_DEFINED
|
||||
#define SkDWriteToPath_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
|
||||
class SkPath;
|
||||
|
||||
#include <dwrite.h>
|
||||
#include <d2d1.h>
|
||||
|
||||
class SkDWriteGeometrySink : public IDWriteGeometrySink {
|
||||
private:
|
||||
LONG fRefCount;
|
||||
SkPath* fPath;
|
||||
|
||||
SkDWriteGeometrySink(const SkDWriteGeometrySink&);
|
||||
SkDWriteGeometrySink& operator=(const SkDWriteGeometrySink&);
|
||||
|
||||
protected:
|
||||
explicit SkDWriteGeometrySink(SkPath* path);
|
||||
virtual ~SkDWriteGeometrySink();
|
||||
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object) SK_OVERRIDE;
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef(void) SK_OVERRIDE;
|
||||
virtual ULONG STDMETHODCALLTYPE Release(void) SK_OVERRIDE;
|
||||
|
||||
virtual void STDMETHODCALLTYPE SetFillMode(D2D1_FILL_MODE fillMode) SK_OVERRIDE;
|
||||
virtual void STDMETHODCALLTYPE SetSegmentFlags(D2D1_PATH_SEGMENT vertexFlags) SK_OVERRIDE;
|
||||
virtual void STDMETHODCALLTYPE BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin) SK_OVERRIDE;
|
||||
virtual void STDMETHODCALLTYPE AddLines(const D2D1_POINT_2F *points, UINT pointsCount) SK_OVERRIDE;
|
||||
virtual void STDMETHODCALLTYPE AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, UINT beziersCount) SK_OVERRIDE;
|
||||
virtual void STDMETHODCALLTYPE EndFigure(D2D1_FIGURE_END figureEnd) SK_OVERRIDE;
|
||||
virtual HRESULT STDMETHODCALLTYPE Close() SK_OVERRIDE;
|
||||
|
||||
static HRESULT Create(SkPath* path, IDWriteGeometrySink** geometryToPath);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user