From da7a944e293d27ec5c7be06b224921ae0058d35a Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Wed, 6 Aug 2014 16:34:40 -0400 Subject: [PATCH] Revert "Remove SkPaintOptionsAndroid" This reverts commit 27fb94999b8eec448423884e1d071e563c4c95d9. Review URL: https://codereview.chromium.org/450513002 --- gyp/core.gypi | 1 + gyp/tests.gypi | 1 + include/core/SkPaint.h | 10 ++ include/core/SkPaintOptionsAndroid.h | 120 ++++++++++++++++++++ include/core/SkPicture.h | 3 +- include/core/SkReadBuffer.h | 1 - src/core/SkPaint.cpp | 69 ++++++++++- src/core/SkPaintOptionsAndroid.cpp | 43 +++++++ src/core/SkScalerContext.cpp | 13 +++ src/core/SkScalerContext.h | 11 ++ src/ports/SkFontConfigInterface_android.cpp | 21 ++-- src/ports/SkFontConfigParser_android.cpp | 48 +++----- src/ports/SkFontConfigParser_android.h | 56 +-------- src/ports/SkFontMgr_android.cpp | 15 +-- tests/AndroidPaintTest.cpp | 75 ++++++++++++ 15 files changed, 380 insertions(+), 107 deletions(-) create mode 100644 include/core/SkPaintOptionsAndroid.h create mode 100644 src/core/SkPaintOptionsAndroid.cpp create mode 100644 tests/AndroidPaintTest.cpp diff --git a/gyp/core.gypi b/gyp/core.gypi index 0e86ea096c..da43a05ff1 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -119,6 +119,7 @@ '<(skia_src_path)/core/SkMipMap.cpp', '<(skia_src_path)/core/SkPackBits.cpp', '<(skia_src_path)/core/SkPaint.cpp', + '<(skia_src_path)/core/SkPaintOptionsAndroid.cpp', '<(skia_src_path)/core/SkPaintPriv.cpp', '<(skia_src_path)/core/SkPaintPriv.h', '<(skia_src_path)/core/SkPatch.cpp', diff --git a/gyp/tests.gypi b/gyp/tests.gypi index 544485feed..035d4181b5 100644 --- a/gyp/tests.gypi +++ b/gyp/tests.gypi @@ -46,6 +46,7 @@ '../tests/AAClipTest.cpp', '../tests/ARGBImageEncoderTest.cpp', + '../tests/AndroidPaintTest.cpp', '../tests/AnnotationTest.cpp', '../tests/AsADashTest.cpp', '../tests/AtomicTest.cpp', diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index 1814cae29d..58cb160ada 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -15,6 +15,9 @@ #include "SkDrawLooper.h" #include "SkMatrix.h" #include "SkXfermode.h" +#ifdef SK_BUILD_FOR_ANDROID +#include "SkPaintOptionsAndroid.h" +#endif class SkAnnotation; class SkAutoGlyphCache; @@ -938,6 +941,11 @@ public: #ifdef SK_BUILD_FOR_ANDROID uint32_t getGenerationID() const; void setGenerationID(uint32_t generationID); + + const SkPaintOptionsAndroid& getPaintOptionsAndroid() const { + return fPaintOptionsAndroid; + } + void setPaintOptionsAndroid(const SkPaintOptionsAndroid& options); #endif // returns true if the paint's settings (e.g. xfermode + alpha) resolve to @@ -1130,6 +1138,8 @@ private: friend class SkCanonicalizePaint; #ifdef SK_BUILD_FOR_ANDROID + SkPaintOptionsAndroid fPaintOptionsAndroid; + // In order for the == operator to work properly this must be the last field // in the struct so that we can do a memcmp to this field's offset. uint32_t fGenerationID; diff --git a/include/core/SkPaintOptionsAndroid.h b/include/core/SkPaintOptionsAndroid.h new file mode 100644 index 0000000000..4d0bae3eb8 --- /dev/null +++ b/include/core/SkPaintOptionsAndroid.h @@ -0,0 +1,120 @@ + +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPaintOptionsAndroid_DEFINED +#define SkPaintOptionsAndroid_DEFINED + +#include "SkTypes.h" +#include "SkString.h" + +class SkReadBuffer; +class SkWriteBuffer; + +/** \class SkLanguage + + The SkLanguage class represents a human written language, and is used by + text draw operations to determine which glyph to draw when drawing + characters with variants (ie Han-derived characters). +*/ +class SkLanguage { +public: + SkLanguage() { } + SkLanguage(const SkString& tag) : fTag(tag) { } + SkLanguage(const char* tag) : fTag(tag) { } + SkLanguage(const char* tag, size_t len) : fTag(tag, len) { } + SkLanguage(const SkLanguage& b) : fTag(b.fTag) { } + + /** Gets a BCP 47 language identifier for this SkLanguage. + @return a BCP 47 language identifier representing this language + */ + const SkString& getTag() const { return fTag; } + + /** Performs BCP 47 fallback to return an SkLanguage one step more general. + @return an SkLanguage one step more general + */ + SkLanguage getParent() const; + + bool operator==(const SkLanguage& b) const { + return fTag == b.fTag; + } + bool operator!=(const SkLanguage& b) const { + return fTag != b.fTag; + } + SkLanguage& operator=(const SkLanguage& b) { + fTag = b.fTag; + return *this; + } + +private: + //! BCP 47 language identifier + SkString fTag; +}; + +class SkPaintOptionsAndroid { +public: + SkPaintOptionsAndroid() { + fFontVariant = kDefault_Variant; + } + + SkPaintOptionsAndroid& operator=(const SkPaintOptionsAndroid& b) { + fLanguage = b.fLanguage; + fFontVariant = b.fFontVariant; + return *this; + } + + bool operator==(const SkPaintOptionsAndroid& b) const { + return !(*this != b); + } + + bool operator!=(const SkPaintOptionsAndroid& b) const { + return fLanguage != b.fLanguage || + fFontVariant != b.fFontVariant; + } + + void flatten(SkWriteBuffer&) const; + void unflatten(SkReadBuffer&); + + /** Return the paint's language value used for drawing text. + @return the paint's language value used for drawing text. + */ + const SkLanguage& getLanguage() const { return fLanguage; } + + /** Set the paint's language value used for drawing text. + @param language set the paint's language value for drawing text. + */ + void setLanguage(const SkLanguage& language) { fLanguage = language; } + void setLanguage(const char* languageTag) { fLanguage = SkLanguage(languageTag); } + + + enum FontVariant { + kDefault_Variant = 0x01, + kCompact_Variant = 0x02, + kElegant_Variant = 0x04, + kLast_Variant = kElegant_Variant, + }; + + /** Return the font variant + @return the font variant used by this paint object + */ + FontVariant getFontVariant() const { return fFontVariant; } + + /** Set the font variant + @param fontVariant set the paint's font variant for choosing fonts + */ + void setFontVariant(FontVariant fontVariant) { + SkASSERT((unsigned)fontVariant <= kLast_Variant); + fFontVariant = fontVariant; + } + +private: + SkLanguage fLanguage; + FontVariant fFontVariant; +}; + +#endif // #ifndef SkPaintOptionsAndroid_DEFINED diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index e0a425f807..c733e532c2 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -231,14 +231,13 @@ private: // V29: Removed SaveFlags parameter from save(). // V30: Remove redundant SkMatrix from SkLocalMatrixShader. // V31: Add a serialized UniqueID to SkImageFilter. - // V32: Removed SkPaintOptionsAndroid from SkPaint // Note: If the picture version needs to be increased then please follow the // steps to generate new SKPs in (only accessible to Googlers): http://goo.gl/qATVcw // Only SKPs within the min/current picture version range (inclusive) can be read. static const uint32_t MIN_PICTURE_VERSION = 19; - static const uint32_t CURRENT_PICTURE_VERSION = 32; + static const uint32_t CURRENT_PICTURE_VERSION = 31; mutable uint32_t fUniqueID; diff --git a/include/core/SkReadBuffer.h b/include/core/SkReadBuffer.h index a760614585..2beb7ac738 100644 --- a/include/core/SkReadBuffer.h +++ b/include/core/SkReadBuffer.h @@ -47,7 +47,6 @@ public: kNoMoreBitmapFlatten_Version = 28, kSimplifyLocalMatrix_Version = 30, kImageFilterUniqueID_Version = 31, - kRemoveAndroidPaintOpts_Version = 32, }; /** diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 3dd87b7aa6..9e53d19e2a 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -21,6 +21,7 @@ #include "SkReadBuffer.h" #include "SkWriteBuffer.h" #include "SkPaintDefaults.h" +#include "SkPaintOptionsAndroid.h" #include "SkPathEffect.h" #include "SkRasterizer.h" #include "SkScalar.h" @@ -54,6 +55,7 @@ enum { kImageFilter_DirtyBit = 1 << 13, kTypeface_DirtyBit = 1 << 14, kAnnotation_DirtyBit = 1 << 15, + kPaintOptionsAndroid_DirtyBit = 1 << 16, }; // define this to get a printf for out-of-range parameter in setters @@ -99,6 +101,7 @@ SkPaint::SkPaint() { fDirtyBits = 0; #ifdef SK_BUILD_FOR_ANDROID + new (&fPaintOptionsAndroid) SkPaintOptionsAndroid; fGenerationID = 0; #endif } @@ -128,6 +131,7 @@ SkPaint::SkPaint(const SkPaint& src) { COPY(fDirtyBits); #ifdef SK_BUILD_FOR_ANDROID + new (&fPaintOptionsAndroid) SkPaintOptionsAndroid(src.fPaintOptionsAndroid); COPY(fGenerationID); #endif @@ -179,6 +183,8 @@ SkPaint& SkPaint::operator=(const SkPaint& src) { COPY(fDirtyBits); #ifdef SK_BUILD_FOR_ANDROID + fPaintOptionsAndroid.~SkPaintOptionsAndroid(); + new (&fPaintOptionsAndroid) SkPaintOptionsAndroid(src.fPaintOptionsAndroid); ++fGenerationID; #endif @@ -208,6 +214,9 @@ bool operator==(const SkPaint& a, const SkPaint& b) { && EQUAL(fWidth) && EQUAL(fMiterLimit) && EQUAL(fBitfieldsUInt) +#ifdef SK_BUILD_FOR_ANDROID + && EQUAL(fPaintOptionsAndroid) +#endif ; #undef EQUAL } @@ -232,6 +241,14 @@ uint32_t SkPaint::getGenerationID() const { void SkPaint::setGenerationID(uint32_t generationID) { fGenerationID = generationID; } + +void SkPaint::setPaintOptionsAndroid(const SkPaintOptionsAndroid& options) { + if (options != fPaintOptionsAndroid) { + fPaintOptionsAndroid = options; + GEN_ID_INC; + fDirtyBits |= kPaintOptionsAndroid_DirtyBit; + } +} #endif void SkPaint::setFilterLevel(FilterLevel level) { @@ -1826,6 +1843,14 @@ void SkPaint::descriptorProc(const SkDeviceProperties* deviceProperties, rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion } +#ifdef SK_BUILD_FOR_ANDROID + char buffer[128]; + SkWriteBuffer androidBuffer(buffer, sizeof(buffer)); + fPaintOptionsAndroid.flatten(androidBuffer); + descSize += androidBuffer.bytesWritten(); + entryCount += 1; +#endif + /////////////////////////////////////////////////////////////////////////// // Now that we're done tweaking the rec, call the PostMakeRec cleanup SkScalerContext::PostMakeRec(*this, &rec); @@ -1838,6 +1863,10 @@ void SkPaint::descriptorProc(const SkDeviceProperties* deviceProperties, desc->init(); desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); +#ifdef SK_BUILD_FOR_ANDROID + add_flattenable(desc, kAndroidOpts_SkDescriptorTag, &androidBuffer); +#endif + if (pe) { add_flattenable(desc, kPathEffect_SkDescriptorTag, &peBuffer); } @@ -1872,6 +1901,11 @@ void SkPaint::descriptorProc(const SkDeviceProperties* deviceProperties, desc1->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); desc2->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); +#ifdef SK_BUILD_FOR_ANDROID + add_flattenable(desc1, kAndroidOpts_SkDescriptorTag, &androidBuffer); + add_flattenable(desc2, kAndroidOpts_SkDescriptorTag, &androidBuffer); +#endif + if (pe) { add_flattenable(desc1, kPathEffect_SkDescriptorTag, &peBuffer); add_flattenable(desc2, kPathEffect_SkDescriptorTag, &peBuffer); @@ -2088,6 +2122,11 @@ void SkPaint::flatten(SkWriteBuffer& buffer) const { asint(this->getImageFilter())) { flatFlags |= kHasEffects_FlatFlag; } +#ifdef SK_BUILD_FOR_ANDROID + if (this->getPaintOptionsAndroid() != SkPaintOptionsAndroid()) { + flatFlags |= kHasNonDefaultPaintOptionsAndroid_FlatFlag; + } +#endif SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize); uint32_t* ptr = buffer.reserve(kPODPaintSize); @@ -2126,6 +2165,11 @@ void SkPaint::flatten(SkWriteBuffer& buffer) const { buffer.writeBool(false); } } +#ifdef SK_BUILD_FOR_ANDROID + if (flatFlags & kHasNonDefaultPaintOptionsAndroid_FlatFlag) { + this->getPaintOptionsAndroid().flatten(buffer); + } +#endif } void SkPaint::unflatten(SkReadBuffer& buffer) { @@ -2184,12 +2228,15 @@ void SkPaint::unflatten(SkReadBuffer& buffer) { this->setImageFilter(NULL); } - if (buffer.isVersionLT(SkReadBuffer::kRemoveAndroidPaintOpts_Version) && - flatFlags & kHasNonDefaultPaintOptionsAndroid_FlatFlag) { - SkString tag; - buffer.readUInt(); - buffer.readString(&tag); - buffer.readBool(); +#ifdef SK_BUILD_FOR_ANDROID + this->setPaintOptionsAndroid(SkPaintOptionsAndroid()); +#endif + if (flatFlags & kHasNonDefaultPaintOptionsAndroid_FlatFlag) { + SkPaintOptionsAndroid options; + options.unflatten(buffer); +#ifdef SK_BUILD_FOR_ANDROID + this->setPaintOptionsAndroid(options); +#endif } } @@ -2648,6 +2695,9 @@ void SkPaint::FlatteningTraits::Flatten(SkWriteBuffer& buffer, const SkPaint& pa #undef F if (dirty & kTypeface_DirtyBit) buffer.writeTypeface(paint.getTypeface()); if (dirty & kAnnotation_DirtyBit) paint.getAnnotation()->writeToBuffer(buffer); +#ifdef SK_BUILD_FOR_ANDROID + if (dirty & kPaintOptionsAndroid_DirtyBit) paint.getPaintOptionsAndroid().flatten(buffer); +#endif } void SkPaint::FlatteningTraits::Unflatten(SkReadBuffer& buffer, SkPaint* paint) { @@ -2682,5 +2732,12 @@ void SkPaint::FlatteningTraits::Unflatten(SkReadBuffer& buffer, SkPaint* paint) if (dirty & kAnnotation_DirtyBit) { paint->setAnnotation(SkAnnotation::Create(buffer))->unref(); } +#ifdef SK_BUILD_FOR_ANDROID + if (dirty & kPaintOptionsAndroid_DirtyBit) { + SkPaintOptionsAndroid options; + options.unflatten(buffer); + paint->setPaintOptionsAndroid(options); + } +#endif SkASSERT(dirty == paint->fDirtyBits); } diff --git a/src/core/SkPaintOptionsAndroid.cpp b/src/core/SkPaintOptionsAndroid.cpp new file mode 100644 index 0000000000..df71ca87a4 --- /dev/null +++ b/src/core/SkPaintOptionsAndroid.cpp @@ -0,0 +1,43 @@ + +/* + * Copyright 2012 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkPaintOptionsAndroid.h" +#include "SkReadBuffer.h" +#include "SkWriteBuffer.h" +#include "SkTDict.h" +#include "SkThread.h" +#include + +SkLanguage SkLanguage::getParent() const { + SkASSERT(!fTag.isEmpty()); + const char* tag = fTag.c_str(); + + // strip off the rightmost "-.*" + const char* parentTagEnd = strrchr(tag, '-'); + if (parentTagEnd == NULL) { + return SkLanguage(); + } + size_t parentTagLen = parentTagEnd - tag; + return SkLanguage(tag, parentTagLen); +} + +void SkPaintOptionsAndroid::flatten(SkWriteBuffer& buffer) const { + buffer.writeUInt(fFontVariant); + buffer.writeString(fLanguage.getTag().c_str()); + // to maintain picture compatibility for the old fUseFontFallbacks variable + buffer.writeBool(false); +} + +void SkPaintOptionsAndroid::unflatten(SkReadBuffer& buffer) { + fFontVariant = (FontVariant)buffer.readUInt(); + SkString tag; + buffer.readString(&tag); + fLanguage = SkLanguage(tag); + // to maintain picture compatibility for the old fUseFontFallbacks variable + buffer.readBool(); +} diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp index db3c0fb2f5..11208fec59 100644 --- a/src/core/SkScalerContext.cpp +++ b/src/core/SkScalerContext.cpp @@ -23,6 +23,10 @@ #include "SkStroke.h" #include "SkThread.h" +#ifdef SK_BUILD_FOR_ANDROID + #include "SkTypeface_android.h" +#endif + #define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3) void SkGlyph::toMask(SkMask* mask) const { @@ -107,6 +111,15 @@ SkScalerContext::SkScalerContext(SkTypeface* typeface, const SkDescriptor* desc) desc->findEntry(kPathEffect_SkDescriptorTag, NULL), desc->findEntry(kMaskFilter_SkDescriptorTag, NULL)); #endif +#ifdef SK_BUILD_FOR_ANDROID + uint32_t len; + const void* data = desc->findEntry(kAndroidOpts_SkDescriptorTag, &len); + if (data) { + SkReadBuffer buffer(data, len); + fPaintOptionsAndroid.unflatten(buffer); + SkASSERT(buffer.offset() == buffer.size()); + } +#endif } SkScalerContext::~SkScalerContext() { diff --git a/src/core/SkScalerContext.h b/src/core/SkScalerContext.h index 609e9dd673..43b5ebfaf6 100644 --- a/src/core/SkScalerContext.h +++ b/src/core/SkScalerContext.h @@ -14,6 +14,10 @@ #include "SkPaint.h" #include "SkTypeface.h" +#ifdef SK_BUILD_FOR_ANDROID + #include "SkPaintOptionsAndroid.h" +#endif + struct SkGlyph; class SkDescriptor; class SkMaskFilter; @@ -258,6 +262,10 @@ private: // never null SkAutoTUnref fTypeface; +#ifdef SK_BUILD_FOR_ANDROID + SkPaintOptionsAndroid fPaintOptionsAndroid; +#endif + // optional object, which may be null SkPathEffect* fPathEffect; SkMaskFilter* fMaskFilter; @@ -289,6 +297,9 @@ private: #define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e') #define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f') #define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't') +#ifdef SK_BUILD_FOR_ANDROID +#define kAndroidOpts_SkDescriptorTag SkSetFourByteTag('a', 'n', 'd', 'r') +#endif /////////////////////////////////////////////////////////////////////////////// diff --git a/src/ports/SkFontConfigInterface_android.cpp b/src/ports/SkFontConfigInterface_android.cpp index af0c0ebdbe..1651ac9c05 100644 --- a/src/ports/SkFontConfigInterface_android.cpp +++ b/src/ports/SkFontConfigInterface_android.cpp @@ -69,8 +69,7 @@ struct FamilyRec { FontRecID fFontRecID[FONT_STYLE_COUNT]; bool fIsFallbackFont; SkString fFallbackName; - SkLanguage fLanguage; - FontVariant fVariant; + SkPaintOptionsAndroid fPaintOptions; }; @@ -253,8 +252,12 @@ SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArrayfIsFallbackFont = family->fIsFallbackFont; - familyRec->fLanguage = family->fLanguage; - familyRec->fVariant = family->fVariant; + familyRec->fPaintOptions = family->fFontFiles[j].fPaintOptions; + + } else if (familyRec->fPaintOptions != family->fFontFiles[j].fPaintOptions) { + SkDebugf("Every font file within a family must have identical" + "language and variant attributes"); + sk_throw(); } // add this font to the current familyRec @@ -302,7 +305,7 @@ SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArraypush(familyRecID); } @@ -337,7 +340,7 @@ void SkFontConfigInterfaceAndroid::addFallbackFamily(FamilyRecID familyRecID) { fDefaultFallbackList.push(familyRecID); // stop here if it is the default language tag - const SkString& languageTag = familyRec.fLanguage.getTag(); + const SkString& languageTag = familyRec.fPaintOptions.getLanguage().getTag(); if (languageTag.isEmpty()) { return; } @@ -508,9 +511,9 @@ bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni, FamilyRecID familyRecID = fallbackFontList->getAt(i); // if it is not one of the accepted variants then move to the next family - int32_t acceptedVariants = kDefault_FontVariant | - kElegant_FontVariant; - if (!(fFontFamilies[familyRecID].fVariant & acceptedVariants)) { + int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant | + SkPaintOptionsAndroid::kElegant_Variant; + if (!(fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & acceptedVariants)) { continue; } diff --git a/src/ports/SkFontConfigParser_android.cpp b/src/ports/SkFontConfigParser_android.cpp index 58aec2d01f..10212e8a07 100644 --- a/src/ports/SkFontConfigParser_android.cpp +++ b/src/ports/SkFontConfigParser_android.cpp @@ -97,9 +97,9 @@ void familyElementHandler(FontFamily* family, const char** attributes) { } else if (nameLen == 7 && !strncmp("variant", name, nameLen)) { // Value should be either elegant or compact. if (valueLen == 7 && !strncmp("elegant", value, valueLen)) { - family->fVariant = kElegant_FontVariant; + family->fVariant = SkPaintOptionsAndroid::kElegant_Variant; } else if (valueLen == 7 && !strncmp("compact", value, valueLen)) { - family->fVariant = kCompact_FontVariant; + family->fVariant = SkPaintOptionsAndroid::kCompact_Variant; } } } @@ -110,6 +110,13 @@ void fontFileNameHandler(void *data, const char *s, int len) { familyData->currentFontInfo->fFileName.set(s, len); } +void familyElementEndHandler(FontFamily* family) { + for (int i = 0; i < family->fFontFiles.count(); i++) { + family->fFontFiles[i].fPaintOptions.setLanguage(family->fLanguage); + family->fFontFiles[i].fPaintOptions.setFontVariant(family->fVariant); + } +} + void fontElementHandler(XML_Parser* parser, FontFileInfo* file, const char** attributes) { // A should have weight (integer) and style (normal, italic) attributes. // NOTE: we ignore the style. @@ -253,6 +260,7 @@ void endElementHandler(void* data, const char* tag) { if (len == 9 && strncmp(tag, "familyset", len) == 0) { familysetElementEndHandler(familyData); } else if (len == 6 && strncmp(tag, "family", len) == 0) { + familyElementEndHandler(familyData->currentFamily); *familyData->families.append() = familyData->currentFamily; familyData->currentFamily = NULL; } else if (len == 4 && !strncmp(tag, "font", len)) { @@ -305,27 +313,14 @@ static void fontFileElementHandler(FamilyData *familyData, const char **attribut int nameLength = strlen(attributeName); int valueLength = strlen(attributeValue); if (nameLength == 7 && strncmp(attributeName, "variant", nameLength) == 0) { - const FontVariant prevVariant = familyData->currentFamily->fVariant; if (valueLength == 7 && strncmp(attributeValue, "elegant", valueLength) == 0) { - familyData->currentFamily->fVariant = kElegant_FontVariant; + newFileInfo.fPaintOptions.setFontVariant(SkPaintOptionsAndroid::kElegant_Variant); } else if (valueLength == 7 && strncmp(attributeValue, "compact", valueLength) == 0) { - familyData->currentFamily->fVariant = kCompact_FontVariant; + newFileInfo.fPaintOptions.setFontVariant(SkPaintOptionsAndroid::kCompact_Variant); } - if (familyData->currentFamily->fFontFiles.count() > 1 && - familyData->currentFamily->fVariant != prevVariant) { - SkDebugf("Every font file within a family must have identical variants"); - sk_throw(); - } - } else if (nameLength == 4 && strncmp(attributeName, "lang", nameLength) == 0) { - SkLanguage prevLang = familyData->currentFamily->fLanguage; - familyData->currentFamily->fLanguage = SkLanguage(attributeValue); - if (familyData->currentFamily->fFontFiles.count() > 1 && - familyData->currentFamily->fLanguage != prevLang) { - SkDebugf("Every font file within a family must have identical languages"); - sk_throw(); - } + newFileInfo.fPaintOptions.setLanguage(attributeValue); } else if (nameLength == 5 && strncmp(attributeName, "index", nameLength) == 0) { int value; if (parseNonNegativeInteger(attributeValue, &value)) { @@ -494,7 +489,9 @@ static void getFallbackFontFamiliesForLocale(SkTDArray &fallbackFon for (int i = 0; i < langSpecificFonts.count(); ++i) { FontFamily* family = langSpecificFonts[i]; - family->fLanguage = SkLanguage(locale); + for (int j = 0; j < family->fFontFiles.count(); ++j) { + family->fFontFiles[j].fPaintOptions.setLanguage(locale); + } *fallbackFonts.append() = family; } } @@ -572,16 +569,3 @@ void SkFontConfigParser::GetTestFontFamilies(SkTDArray &fontFamilie *fontFamilies.append() = fallbackFonts[i]; } } - -SkLanguage SkLanguage::getParent() const { - SkASSERT(!fTag.isEmpty()); - const char* tag = fTag.c_str(); - - // strip off the rightmost "-.*" - const char* parentTagEnd = strrchr(tag, '-'); - if (parentTagEnd == NULL) { - return SkLanguage(); - } - size_t parentTagLen = parentTagEnd - tag; - return SkLanguage(tag, parentTagLen); -} diff --git a/src/ports/SkFontConfigParser_android.h b/src/ports/SkFontConfigParser_android.h index 5f9279f632..4df8d7e725 100644 --- a/src/ports/SkFontConfigParser_android.h +++ b/src/ports/SkFontConfigParser_android.h @@ -8,62 +8,18 @@ #ifndef SKFONTCONFIGPARSER_ANDROID_H_ #define SKFONTCONFIGPARSER_ANDROID_H_ +#include "SkTypes.h" + +#include "SkPaintOptionsAndroid.h" #include "SkString.h" #include "SkTDArray.h" -/** \class SkLanguage - - The SkLanguage class represents a human written language, and is used by - text draw operations to determine which glyph to draw when drawing - characters with variants (ie Han-derived characters). -*/ -class SkLanguage { -public: - SkLanguage() { } - SkLanguage(const SkString& tag) : fTag(tag) { } - SkLanguage(const char* tag) : fTag(tag) { } - SkLanguage(const char* tag, size_t len) : fTag(tag, len) { } - SkLanguage(const SkLanguage& b) : fTag(b.fTag) { } - - /** Gets a BCP 47 language identifier for this SkLanguage. - @return a BCP 47 language identifier representing this language - */ - const SkString& getTag() const { return fTag; } - - /** Performs BCP 47 fallback to return an SkLanguage one step more general. - @return an SkLanguage one step more general - */ - SkLanguage getParent() const; - - bool operator==(const SkLanguage& b) const { - return fTag == b.fTag; - } - bool operator!=(const SkLanguage& b) const { - return fTag != b.fTag; - } - SkLanguage& operator=(const SkLanguage& b) { - fTag = b.fTag; - return *this; - } - -private: - //! BCP 47 language identifier - SkString fTag; -}; - -enum FontVariants { - kDefault_FontVariant = 0x01, - kCompact_FontVariant = 0x02, - kElegant_FontVariant = 0x04, - kLast_FontVariant = kElegant_FontVariant, -}; -typedef uint32_t FontVariant; - struct FontFileInfo { FontFileInfo() : fIndex(0), fWeight(0) { } SkString fFileName; int fIndex; + SkPaintOptionsAndroid fPaintOptions; int fWeight; }; @@ -77,14 +33,14 @@ struct FontFileInfo { */ struct FontFamily { FontFamily() - : fVariant(kDefault_FontVariant) + : fVariant(SkPaintOptionsAndroid::kDefault_Variant) , order(-1) , fIsFallbackFont(false) { } SkTArray fNames; SkTArray fFontFiles; SkLanguage fLanguage; - FontVariant fVariant; + SkPaintOptionsAndroid::FontVariant fVariant; int order; // only used internally by SkFontConfigParser bool fIsFallbackFont; }; diff --git a/src/ports/SkFontMgr_android.cpp b/src/ports/SkFontMgr_android.cpp index 7ce7cb09b6..1ab2f29642 100644 --- a/src/ports/SkFontMgr_android.cpp +++ b/src/ports/SkFontMgr_android.cpp @@ -61,7 +61,7 @@ public: bool isFixedPitch, const SkString familyName, const SkLanguage& lang, - FontVariant variantStyle) + uint32_t variantStyle) : INHERITED(index, style, isFixedPitch, familyName) , fPathName(pathName) , fLang(lang) @@ -82,7 +82,7 @@ public: const SkString fPathName; const SkLanguage fLang; - const FontVariant fVariantStyle; + const uint32_t fVariantStyle; typedef SkTypeface_Android INHERITED; }; @@ -153,10 +153,11 @@ public: continue; } - const SkLanguage& lang = family.fLanguage; - uint32_t variant = family.fVariant; - if (kDefault_FontVariant == variant) { - variant = kCompact_FontVariant | kElegant_FontVariant; + const SkLanguage& lang = fontFile.fPaintOptions.getLanguage(); + uint32_t variant = fontFile.fPaintOptions.getFontVariant(); + if (SkPaintOptionsAndroid::kDefault_Variant == variant) { + variant = SkPaintOptionsAndroid::kCompact_Variant | + SkPaintOptionsAndroid::kElegant_Variant; } // The first specified family name overrides the family name found in the font. @@ -334,7 +335,7 @@ protected: // TODO: add 'is_elegant' and 'is_compact' bits to 'style' request. // For compatibility, try 'elegant' fonts first in fallback. - uint32_t variantMask = kElegant_FontVariant; + uint32_t variantMask = SkPaintOptionsAndroid::kElegant_Variant; // The first time match anything in the mask, second time anything not in the mask. for (bool maskMatches = true; maskMatches != false; maskMatches = false) { diff --git a/tests/AndroidPaintTest.cpp b/tests/AndroidPaintTest.cpp new file mode 100644 index 0000000000..f5cf84f4f3 --- /dev/null +++ b/tests/AndroidPaintTest.cpp @@ -0,0 +1,75 @@ +// SkPaints only have an SkPaintOptionsAndroid if SK_BUILD_FOR_ANDROID is true. +#ifdef SK_BUILD_FOR_ANDROID + +#include "SkReadBuffer.h" +#include "SkWriteBuffer.h" +#include "SkPaint.h" +#include "SkPaintOptionsAndroid.h" +#include "Test.h" + +static size_t Reconstruct(const SkPaint& src, SkPaint* dst) { + SkWriteBuffer writer; + src.flatten(writer); + + const size_t size = writer.bytesWritten(); + SkAutoMalloc bytes(size); + writer.writeToMemory(bytes.get()); + + SkReadBuffer reader(bytes.get(), size); + dst->unflatten(reader); + + return size; +} + +DEF_TEST(AndroidOptionsSerialization, reporter) { + // We want to make sure that Android's paint options survive a flatten/unflatten round trip. + // These are all non-default options. + SkPaintOptionsAndroid options; + options.setLanguage("ja-JP"); + options.setFontVariant(SkPaintOptionsAndroid::kElegant_Variant); + + SkPaint paint; + paint.setPaintOptionsAndroid(options); + + SkPaint reconstructed; + Reconstruct(paint, &reconstructed); + + REPORTER_ASSERT(reporter, options == reconstructed.getPaintOptionsAndroid()); +} + +DEF_TEST(AndroidOptionsSerializationReverse, reporter) { + // Opposite test of above: make sure the serialized default values of a paint overwrite + // non-default values on the paint we're unflattening into. + const SkPaint defaultOptions; + + SkPaintOptionsAndroid options; + options.setLanguage("ja-JP"); + options.setFontVariant(SkPaintOptionsAndroid::kElegant_Variant); + SkPaint nonDefaultOptions; + nonDefaultOptions.setPaintOptionsAndroid(options); + + Reconstruct(defaultOptions, &nonDefaultOptions); + + REPORTER_ASSERT(reporter, + defaultOptions.getPaintOptionsAndroid() == + nonDefaultOptions.getPaintOptionsAndroid()); +} + +DEF_TEST(AndroidOptionsSize, reporter) { + // A paint with default android options should serialize to something smaller than + // a paint with non-default android options. + + SkPaint defaultOptions; + + SkPaintOptionsAndroid options; + options.setLanguage("ja-JP"); + SkPaint nonDefaultOptions; + nonDefaultOptions.setPaintOptionsAndroid(options); + + SkPaint dummy; + + REPORTER_ASSERT(reporter, + Reconstruct(defaultOptions, &dummy) < Reconstruct(nonDefaultOptions, &dummy)); +} + +#endif // SK_BUILD_FOR_ANDROID