aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-05-07 15:28:15 +0000
committerGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-05-07 15:28:15 +0000
commitb5e34e22aa0e019e25f9f913f0e119a9a97e5562 (patch)
treec064647d66956478b92bf2adcb16025daafc29b3
parent2983ddd4b57a05e3262fe2c1964a34f1717a5a1c (diff)
XPS ttc handling.
R=reed@google.com Author: bungeman@google.com Review URL: https://chromiumcodereview.appspot.com/14873006 git-svn-id: http://skia.googlecode.com/svn/trunk@9037 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--gyp/sfnt.gyp1
-rw-r--r--gyp/xps.gyp1
-rw-r--r--include/core/SkTemplates.h54
-rw-r--r--include/device/xps/SkConstexprMath.h6
-rw-r--r--include/device/xps/SkXPSDevice.h3
-rw-r--r--src/device/xps/SkXPSDevice.cpp87
-rw-r--r--src/sfnt/SkOTTable_name.cpp13
-rw-r--r--src/sfnt/SkTTCFHeader.h56
8 files changed, 183 insertions, 38 deletions
diff --git a/gyp/sfnt.gyp b/gyp/sfnt.gyp
index 1abae537bb..438f33e8e6 100644
--- a/gyp/sfnt.gyp
+++ b/gyp/sfnt.gyp
@@ -34,6 +34,7 @@
'../src/sfnt/SkOTUtils.h',
'../src/sfnt/SkPreprocessorSeq.h',
'../src/sfnt/SkSFNTHeader.h',
+ '../src/sfnt/SkTTCFHeader.h',
'../src/sfnt/SkTypedEnum.h',
'../src/sfnt/SkOTTable_name.cpp',
diff --git a/gyp/xps.gyp b/gyp/xps.gyp
index e5b7c0d6bb..376874205c 100644
--- a/gyp/xps.gyp
+++ b/gyp/xps.gyp
@@ -8,6 +8,7 @@
'dependencies': [
'skia_base_libs.gyp:skia_base_libs',
'images.gyp:images',
+ 'sfnt.gyp:sfnt',
],
'include_dirs': [
'../include/device/xps',
diff --git a/include/core/SkTemplates.h b/include/core/SkTemplates.h
index 566834cab3..5eb7885425 100644
--- a/include/core/SkTemplates.h
+++ b/include/core/SkTemplates.h
@@ -46,6 +46,24 @@ template <typename T> struct SkTConstType<T, true> {
};
///@}
+/**
+ * Returns a pointer to a D which comes immediately after S[count].
+ */
+template <typename D, typename S> static D* SkTAfter(S* ptr, size_t count = 1) {
+ return reinterpret_cast<D*>(ptr + count);
+}
+
+/**
+ * Returns a pointer to a D which comes byteOffset bytes after S.
+ */
+template <typename D, typename S> static D* SkTAddOffset(S* ptr, size_t byteOffset) {
+ // The intermediate char* has the same const-ness as D as this produces better error messages.
+ // This relies on the fact that reinterpret_cast can add constness, but cannot remove it.
+ return reinterpret_cast<D*>(
+ reinterpret_cast<typename SkTConstType<char, SkTIsConst<D>::value>::type*>(ptr) + byteOffset
+ );
+}
+
/** \class SkAutoTCallVProc
Call a function when this goes out of scope. The template uses two
@@ -252,12 +270,18 @@ private:
char fStorage[N * sizeof(T)];
};
-/** Allocate a temp array on the stack/heap.
- Does NOT call any constructors/destructors on T (i.e. T must be POD)
-*/
+/** Manages an array of T elements, freeing the array in the destructor.
+ * Does NOT call any constructors/destructors on T (T must be POD).
+ */
template <typename T> class SkAutoTMalloc : SkNoncopyable {
public:
- SkAutoTMalloc(size_t count) {
+ /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */
+ explicit SkAutoTMalloc(T* ptr = NULL) {
+ fPtr = ptr;
+ }
+
+ /** Allocates space for 'count' Ts. */
+ explicit SkAutoTMalloc(size_t count) {
fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
}
@@ -265,8 +289,13 @@ public:
sk_free(fPtr);
}
- // doesn't preserve contents
- void reset (size_t count) {
+ /** Resize the memory area pointed to by the current ptr preserving contents. */
+ void realloc(size_t count) {
+ fPtr = reinterpret_cast<T*>(sk_realloc_throw(fPtr, count * sizeof(T)));
+ }
+
+ /** Resize the memory area pointed to by the current ptr without preserving contents. */
+ void reset(size_t count) {
sk_free(fPtr);
fPtr = fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
}
@@ -289,8 +318,19 @@ public:
return fPtr[index];
}
+ /**
+ * Transfer ownership of the ptr to the caller, setting the internal
+ * pointer to NULL. Note that this differs from get(), which also returns
+ * the pointer, but it does not transfer ownership.
+ */
+ T* detach() {
+ T* ptr = fPtr;
+ fPtr = NULL;
+ return ptr;
+ }
+
private:
- T* fPtr;
+ T* fPtr;
};
template <size_t N, typename T> class SK_API SkAutoSTMalloc : SkNoncopyable {
diff --git a/include/device/xps/SkConstexprMath.h b/include/device/xps/SkConstexprMath.h
index 65b70b6eea..9625d5112b 100644
--- a/include/device/xps/SkConstexprMath.h
+++ b/include/device/xps/SkConstexprMath.h
@@ -46,7 +46,9 @@ struct SK_2N1<1> {
*/
#define SK_DIGITS_IN(t) SK_BASE_N_DIGITS_IN(10, (t))
-//! a > b ? a : b
-#define SK_MAX(a,b) (((a) > (b)) ? (a) : (b))
+// Compile-time constant maximum value of two unsigned values.
+template <uintmax_t a, uintmax_t b> struct SkTUMax {
+ static const uintmax_t value = (b < a) ? a : b;
+};
#endif
diff --git a/include/device/xps/SkXPSDevice.h b/include/device/xps/SkXPSDevice.h
index 228e90539b..8ed3180c5c 100644
--- a/include/device/xps/SkXPSDevice.h
+++ b/include/device/xps/SkXPSDevice.h
@@ -150,6 +150,7 @@ private:
class TypefaceUse : ::SkNoncopyable {
public:
SkFontID typefaceId;
+ int ttcIndex;
SkStream* fontData;
IXpsOMFontResource* xpsFont;
SkBitSet* glyphsUsed;
@@ -247,7 +248,7 @@ private:
const SkDraw& d,
IXpsOMObjectFactory* xpsFactory,
IXpsOMCanvas* canvas,
- IXpsOMFontResource* font,
+ TypefaceUse* font,
LPCWSTR text,
XPS_GLYPH_INDEX* xpsGlyphs,
UINT32 xpsGlyphsLen,
diff --git a/src/device/xps/SkXPSDevice.cpp b/src/device/xps/SkXPSDevice.cpp
index ddd4a0d107..d7a559865f 100644
--- a/src/device/xps/SkXPSDevice.cpp
+++ b/src/device/xps/SkXPSDevice.cpp
@@ -22,6 +22,7 @@
#include "SkData.h"
#include "SkDraw.h"
#include "SkDrawProcs.h"
+#include "SkEndian.h"
#include "SkFontHost.h"
#include "SkGlyphCache.h"
#include "SkHRESULT.h"
@@ -31,12 +32,14 @@
#include "SkPaint.h"
#include "SkPoint.h"
#include "SkRasterizer.h"
+#include "SkSFNTHeader.h"
#include "SkShader.h"
#include "SkSize.h"
#include "SkStream.h"
#include "SkTDArray.h"
#include "SkTLazy.h"
#include "SkTScopedComPtr.h"
+#include "SkTTCFHeader.h"
#include "SkTypefacePriv.h"
#include "SkUtils.h"
#include "SkXPSDevice.h"
@@ -80,6 +83,7 @@ static int format_guid(const GUID& guid,
guid.Data4[6],
guid.Data4[7]);
}
+
/**
Creates a GUID based id and places it into buffer.
buffer should have space for at least GUID_ID_LEN wide characters.
@@ -179,10 +183,10 @@ HRESULT SkXPSDevice::createXpsThumbnail(IXpsOMPage* page,
"Could not create thumbnail generator.");
SkTScopedComPtr<IOpcPartUri> partUri;
- static const size_t size = SK_MAX(
+ static const size_t size = SkTUMax<
SK_ARRAY_COUNT(L"/Documents/1/Metadata/.png") + SK_DIGITS_IN(pageNum),
SK_ARRAY_COUNT(L"/Metadata/" L_GUID_ID L".png")
- );
+ >::value;
wchar_t buffer[size];
if (pageNum > 0) {
swprintf_s(buffer, size, L"/Documents/1/Metadata/%u.png", pageNum);
@@ -334,18 +338,20 @@ static HRESULT subset_typeface(SkXPSDevice::TypefaceUse* current) {
SkTDArray<unsigned short> keepList;
current->glyphsUsed->exportTo(&keepList);
+ int ttcCount = (current->ttcIndex + 1);
+
//The following are declared with the types required by CreateFontPackage.
- unsigned char *puchFontPackageBuffer;
- unsigned long pulFontPackageBufferSize;
- unsigned long pulBytesWritten;
+ unsigned char *fontPackageBufferRaw = NULL;
+ unsigned long fontPackageBufferSize;
+ unsigned long bytesWritten;
unsigned long result = CreateFontPackage(
(unsigned char *) current->fontData->getMemoryBase(),
(unsigned long) current->fontData->getLength(),
- &puchFontPackageBuffer,
- &pulFontPackageBufferSize,
- &pulBytesWritten,
- TTFCFP_FLAGS_SUBSET | TTFCFP_FLAGS_GLYPHLIST,// | TTFCFP_FLAGS_TTC,
- 0,//TTC index
+ &fontPackageBufferRaw,
+ &fontPackageBufferSize,
+ &bytesWritten,
+ TTFCFP_FLAGS_SUBSET | TTFCFP_FLAGS_GLYPHLIST | (ttcCount > 0 ? TTFCFP_FLAGS_TTC : 0),
+ current->ttcIndex,
TTFCFP_SUBSET,
0,
0,
@@ -356,15 +362,51 @@ static HRESULT subset_typeface(SkXPSDevice::TypefaceUse* current) {
sk_realloc_throw,
sk_free,
NULL);
+ SkAutoTMalloc<unsigned char> fontPackageBuffer(fontPackageBufferRaw);
if (result != NO_ERROR) {
SkDEBUGF(("CreateFontPackage Error %lu", result));
return E_UNEXPECTED;
}
- SkMemoryStream* newStream = new SkMemoryStream;
- newStream->setMemoryOwned(puchFontPackageBuffer, pulBytesWritten);
+ // If it was originally a ttc, keep it a ttc.
+ // CreateFontPackage over-allocates, realloc usually decreases the size substantially.
+ size_t extra;
+ if (ttcCount > 0) {
+ // Create space for a ttc header.
+ extra = sizeof(SkTTCFHeader) + (ttcCount * sizeof(SK_OT_ULONG));
+ fontPackageBuffer.realloc(bytesWritten + extra);
+ //overlap is certain, use memmove
+ memmove(fontPackageBuffer.get() + extra, fontPackageBuffer.get(), bytesWritten);
+
+ // Write the ttc header.
+ SkTTCFHeader* ttcfHeader = reinterpret_cast<SkTTCFHeader*>(fontPackageBuffer.get());
+ ttcfHeader->ttcTag = SkTTCFHeader::TAG;
+ ttcfHeader->version = SkTTCFHeader::version_1;
+ ttcfHeader->numOffsets = SkEndian_SwapBE32(ttcCount);
+ SK_OT_ULONG* offsetPtr = SkTAfter<SK_OT_ULONG>(ttcfHeader);
+ for (int i = 0; i < ttcCount; ++i, ++offsetPtr) {
+ *offsetPtr = SkEndian_SwapBE32(extra);
+ }
+
+ // Fix up offsets in sfnt table entries.
+ SkSFNTHeader* sfntHeader = SkTAddOffset<SkSFNTHeader>(fontPackageBuffer.get(), extra);
+ int numTables = SkEndian_SwapBE16(sfntHeader->numTables);
+ SkSFNTHeader::TableDirectoryEntry* tableDirectory =
+ SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader);
+ for (int i = 0; i < numTables; ++i, ++tableDirectory) {
+ tableDirectory->offset = SkEndian_SwapBE32(
+ SkEndian_SwapBE32(tableDirectory->offset) + extra);
+ }
+ } else {
+ extra = 0;
+ fontPackageBuffer.realloc(bytesWritten);
+ }
+
+ SkAutoTUnref<SkMemoryStream> newStream(new SkMemoryStream());
+ newStream->setMemoryOwned(fontPackageBuffer.detach(), bytesWritten + extra);
+
SkTScopedComPtr<IStream> newIStream;
- SkIStream::CreateFromSkStream(newStream, true, &newIStream);
+ SkIStream::CreateFromSkStream(newStream.detach(), true, &newIStream);
XPS_FONT_EMBEDDING embedding;
HRM(current->xpsFont->GetEmbeddingOption(&embedding),
@@ -2034,7 +2076,8 @@ HRESULT SkXPSDevice::CreateTypefaceUse(const SkPaint& paint,
XPS_FONT_EMBEDDING embedding = XPS_FONT_EMBEDDING_RESTRICTED;
SkTScopedComPtr<IStream> fontStream;
- SkStream* fontData = typeface->openStream(NULL);
+ int ttcIndex;
+ SkStream* fontData = typeface->openStream(&ttcIndex);
HRM(SkIStream::CreateFromSkStream(fontData, true, &fontStream),
"Could not create font stream.");
@@ -2057,8 +2100,15 @@ HRESULT SkXPSDevice::CreateTypefaceUse(const SkPaint& paint,
&xpsFontResource),
"Could not create font resource.");
+ //TODO: change openStream to return -1 for non-ttc, get rid of this.
+ uint8_t* data = (uint8_t*)fontData->getMemoryBase();
+ bool isTTC = (data &&
+ fontData->getLength() >= sizeof(SkTTCFHeader) &&
+ ((SkTTCFHeader*)data)->ttcTag == SkTTCFHeader::TAG);
+
TypefaceUse& newTypefaceUse = this->fTypefaces.push_back();
newTypefaceUse.typefaceId = typefaceID;
+ newTypefaceUse.ttcIndex = isTTC ? ttcIndex : -1;
newTypefaceUse.fontData = fontData;
newTypefaceUse.xpsFont = xpsFontResource.release();
@@ -2074,7 +2124,7 @@ HRESULT SkXPSDevice::CreateTypefaceUse(const SkPaint& paint,
HRESULT SkXPSDevice::AddGlyphs(const SkDraw& d,
IXpsOMObjectFactory* xpsFactory,
IXpsOMCanvas* canvas,
- IXpsOMFontResource* font,
+ TypefaceUse* font,
LPCWSTR text,
XPS_GLYPH_INDEX* xpsGlyphs,
UINT32 xpsGlyphsLen,
@@ -2084,7 +2134,8 @@ HRESULT SkXPSDevice::AddGlyphs(const SkDraw& d,
const SkMatrix& transform,
const SkPaint& paint) {
SkTScopedComPtr<IXpsOMGlyphs> glyphs;
- HRM(xpsFactory->CreateGlyphs(font, &glyphs), "Could not create glyphs.");
+ HRM(xpsFactory->CreateGlyphs(font->xpsFont, &glyphs), "Could not create glyphs.");
+ HRM(glyphs->SetFontFaceIndex(font->ttcIndex), "Could not set glyph font face index.");
//XPS uses affine transformations for everything...
//...except positioning text.
@@ -2282,7 +2333,7 @@ void SkXPSDevice::drawText(const SkDraw& d,
HRV(AddGlyphs(d,
this->fXpsFactory.get(),
this->fCurrentXpsCanvas.get(),
- typeface->xpsFont,
+ typeface,
NULL,
procs.xpsGlyphs.begin(), procs.xpsGlyphs.count(),
&origin,
@@ -2334,7 +2385,7 @@ void SkXPSDevice::drawPosText(const SkDraw& d,
HRV(AddGlyphs(d,
this->fXpsFactory.get(),
this->fCurrentXpsCanvas.get(),
- typeface->xpsFont,
+ typeface,
NULL,
procs.xpsGlyphs.begin(), procs.xpsGlyphs.count(),
&origin,
diff --git a/src/sfnt/SkOTTable_name.cpp b/src/sfnt/SkOTTable_name.cpp
index 177cd8fd7c..0b309cd47d 100644
--- a/src/sfnt/SkOTTable_name.cpp
+++ b/src/sfnt/SkOTTable_name.cpp
@@ -10,6 +10,7 @@
#include "SkEndian.h"
#include "SkString.h"
#include "SkTSearch.h"
+#include "SkTemplates.h"
#include "SkUtils.h"
static SkUnichar SkUTF16BE_NextUnichar(const uint16_t** srcPtr) {
@@ -435,14 +436,6 @@ int BCP47FromLanguageIdCompare(const BCP47FromLanguageId* a, const BCP47FromLang
}
}
-template <typename D, typename S> static D* SkTAfter(S const * const ptr, size_t count = 1) {
- return (D*)(ptr + count);
-}
-
-template <typename D, typename S> static D* SkTAddOffset(S const * const ptr, size_t byteOffset) {
- return (D*)((char*)ptr + byteOffset);
-}
-
bool SkOTTableName::Iterator::next(SkOTTableName::Iterator::Record& record) {
const size_t nameRecordsCount = SkEndian_SwapBE16(fName.count);
const SkOTTableName::Record* nameRecords = SkTAfter<const SkOTTableName::Record>(&fName);
@@ -459,12 +452,12 @@ bool SkOTTableName::Iterator::next(SkOTTableName::Iterator::Record& record) {
} while (fType != -1 && nameRecord->nameID.fontSpecific != fType);
const uint16_t stringTableOffset = SkEndian_SwapBE16(fName.stringOffset);
- const char* stringTable = SkTAddOffset<char>(&fName, stringTableOffset);
+ const char* stringTable = SkTAddOffset<const char>(&fName, stringTableOffset);
// Decode the name into UTF-8.
const uint16_t nameOffset = SkEndian_SwapBE16(nameRecord->offset);
const uint16_t nameLength = SkEndian_SwapBE16(nameRecord->length);
- const char* nameString = SkTAddOffset<char>(stringTable, nameOffset);
+ const char* nameString = SkTAddOffset<const char>(stringTable, nameOffset);
switch (nameRecord->platformID.value) {
case SkOTTableName::Record::PlatformID::Windows:
SkASSERT(SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2
diff --git a/src/sfnt/SkTTCFHeader.h b/src/sfnt/SkTTCFHeader.h
new file mode 100644
index 0000000000..ffe792b857
--- /dev/null
+++ b/src/sfnt/SkTTCFHeader.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkTTCFHeader_DEFINED
+#define SkTTCFHeader_DEFINED
+
+#include "SkOTTableTypes.h"
+
+#pragma pack(push, 1)
+
+struct SkTTCFHeader {
+ SK_SFNT_ULONG ttcTag;
+ static const SK_OT_CHAR TAG0 = 't';
+ static const SK_OT_CHAR TAG1 = 't';
+ static const SK_OT_CHAR TAG2 = 'c';
+ static const SK_OT_CHAR TAG3 = 'f';
+ static const SK_OT_ULONG TAG = SkOTTableTAG<SkTTCFHeader>::value;
+
+ SK_OT_Fixed version;
+ static const SK_OT_Fixed version_1 = SkTEndian_SwapBE32(1 << 16);
+ static const SK_OT_Fixed version_2 = SkTEndian_SwapBE32(2 << 16);
+
+ SK_OT_ULONG numOffsets;
+ //SK_OT_ULONG offset[numOffsets]
+
+ struct Version2Ext {
+ SK_OT_ULONG dsigType;
+ struct dsigType_None {
+ static const SK_OT_CHAR TAG0 = 0;
+ static const SK_OT_CHAR TAG1 = 0;
+ static const SK_OT_CHAR TAG2 = 0;
+ static const SK_OT_CHAR TAG3 = 0;
+ static const SK_OT_ULONG TAG = SkOTTableTAG<dsigType_None>::value;
+ };
+ struct dsigType_Format1 {
+ static const SK_OT_CHAR TAG0 = 'D';
+ static const SK_OT_CHAR TAG1 = 'S';
+ static const SK_OT_CHAR TAG2 = 'I';
+ static const SK_OT_CHAR TAG3 = 'G';
+ static const SK_OT_ULONG TAG = SkOTTableTAG<dsigType_Format1>::value;
+ };
+ SK_OT_ULONG dsigLength; //Length of DSIG table (in bytes).
+ SK_OT_ULONG dsigOffset; //Offset of DSIG table from the beginning of file (in bytes).
+ };// version2ext (if version == version_2)
+};
+
+#pragma pack(pop)
+
+
+SK_COMPILE_ASSERT(sizeof(SkTTCFHeader) == 12, sizeof_SkTTCFHeader_not_12);
+
+#endif