diff options
author | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-05-07 15:28:15 +0000 |
---|---|---|
committer | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-05-07 15:28:15 +0000 |
commit | b5e34e22aa0e019e25f9f913f0e119a9a97e5562 (patch) | |
tree | c064647d66956478b92bf2adcb16025daafc29b3 | |
parent | 2983ddd4b57a05e3262fe2c1964a34f1717a5a1c (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.gyp | 1 | ||||
-rw-r--r-- | gyp/xps.gyp | 1 | ||||
-rw-r--r-- | include/core/SkTemplates.h | 54 | ||||
-rw-r--r-- | include/device/xps/SkConstexprMath.h | 6 | ||||
-rw-r--r-- | include/device/xps/SkXPSDevice.h | 3 | ||||
-rw-r--r-- | src/device/xps/SkXPSDevice.cpp | 87 | ||||
-rw-r--r-- | src/sfnt/SkOTTable_name.cpp | 13 | ||||
-rw-r--r-- | src/sfnt/SkTTCFHeader.h | 56 |
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 |