diff options
Diffstat (limited to 'WebCore/platform/graphics/mac')
-rw-r--r-- | WebCore/platform/graphics/mac/Canvas3DLayer.mm | 10 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/ComplexTextController.cpp | 65 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/ComplexTextController.h | 31 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp | 67 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp | 59 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp | 181 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/GraphicsContextMac.mm | 52 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/GraphicsLayerCA.h | 161 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/GraphicsLayerCA.mm | 956 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h | 18 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm | 74 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/SimpleFontDataMac.mm | 29 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/WebLayer.mm | 7 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/WebTiledLayer.mm | 7 |
14 files changed, 1273 insertions, 444 deletions
diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.mm b/WebCore/platform/graphics/mac/Canvas3DLayer.mm index 94819d4..59a7384 100644 --- a/WebCore/platform/graphics/mac/Canvas3DLayer.mm +++ b/WebCore/platform/graphics/mac/Canvas3DLayer.mm @@ -33,8 +33,9 @@ #import "GraphicsLayer.h" #import <QuartzCore/QuartzCore.h> #import <OpenGL/OpenGL.h> +#import <wtf/FastMalloc.h> #import <wtf/RetainPtr.h> -#include <wtf/FastMalloc.h> +#import <wtf/UnusedParam.h> using namespace WebCore; @@ -140,6 +141,13 @@ static void freeData(void *, const void *data, size_t /* size */) return image; } +- (void)display +{ + [super display]; + if (m_layerOwner) + m_layerOwner->didDisplay(self); +} + @end @implementation Canvas3DLayer(WebLayerAdditions) diff --git a/WebCore/platform/graphics/mac/ComplexTextController.cpp b/WebCore/platform/graphics/mac/ComplexTextController.cpp index 265b2c3..7d12b61 100644 --- a/WebCore/platform/graphics/mac/ComplexTextController.cpp +++ b/WebCore/platform/graphics/mac/ComplexTextController.cpp @@ -29,6 +29,13 @@ #include "Font.h" #include "TextBreakIterator.h" +#include <wtf/StdLibExtras.h> + +#if defined(BUILDING_ON_LEOPARD) +// Undefined when compiling agains the 10.5 SDK. +#define kCTVersionNumber10_6 0x00030000 +#endif + using namespace std; namespace WebCore { @@ -106,7 +113,7 @@ int ComplexTextController::offsetForPosition(int h, bool includePartialGlyphs) else hitGlyphEnd = max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : complexTextRun.stringLength()); - // FIXME: Instead of dividing the glyph's advance equially between the characters, this + // FIXME: Instead of dividing the glyph's advance equally between the characters, this // could use the glyph's "ligature carets". However, there is no Core Text API to get the // ligature carets. CFIndex hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance); @@ -263,6 +270,62 @@ void ComplexTextController::collectComplexTextRuns() collectComplexTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); } +#if USE(CORE_TEXT) && USE(ATSUI) +static inline bool shouldUseATSUIAPI() +{ + enum TypeRenderingAPIToUse { UnInitialized, UseATSUI, UseCoreText }; + DEFINE_STATIC_LOCAL(TypeRenderingAPIToUse, apiToUse, (UnInitialized)); + + if (UNLIKELY(apiToUse == UnInitialized)) { + if (&CTGetCoreTextVersion != 0 && CTGetCoreTextVersion() >= kCTVersionNumber10_6) + apiToUse = UseCoreText; + else + apiToUse = UseATSUI; + } + + return apiToUse == UseATSUI; +} +#endif + +CFIndex ComplexTextController::ComplexTextRun::indexAt(size_t i) const +{ +#if USE(CORE_TEXT) && USE(ATSUI) + return shouldUseATSUIAPI() ? m_atsuiIndices[i] : m_coreTextIndices[i]; +#elif USE(ATSUI) + return m_atsuiIndices[i]; +#elif USE(CORE_TEXT) + return m_coreTextIndices[i]; +#endif +} + +void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) +{ +#if USE(CORE_TEXT) && USE(ATSUI) + if (shouldUseATSUIAPI()) + return collectComplexTextRunsForCharactersATSUI(cp, length, stringLocation, fontData); + return collectComplexTextRunsForCharactersCoreText(cp, length, stringLocation, fontData); +#elif USE(ATSUI) + return collectComplexTextRunsForCharactersATSUI(cp, length, stringLocation, fontData); +#elif USE(CORE_TEXT) + return collectComplexTextRunsForCharactersCoreText(cp, length, stringLocation, fontData); +#endif +} + +ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) + : m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) +{ +#if USE(CORE_TEXT) && USE(ATSUI) + shouldUseATSUIAPI() ? createTextRunFromFontDataATSUI(ltr) : createTextRunFromFontDataCoreText(ltr); +#elif USE(ATSUI) + createTextRunFromFontDataATSUI(ltr); +#elif USE(CORE_TEXT) + createTextRunFromFontDataCoreText(ltr); +#endif +} + void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) { if (static_cast<int>(offset) > m_end) diff --git a/WebCore/platform/graphics/mac/ComplexTextController.h b/WebCore/platform/graphics/mac/ComplexTextController.h index 7a915e2..3fec18a 100644 --- a/WebCore/platform/graphics/mac/ComplexTextController.h +++ b/WebCore/platform/graphics/mac/ComplexTextController.h @@ -39,6 +39,11 @@ class Font; class SimpleFontData; class TextRun; +// ComplexTextController is responsible for rendering and measuring glyphs for +// complex scripts on OS X. +// The underlying API can be selected at compile time based on USE(ATSUI) and +// USE(CORE_TEXT). If both are defined then the Core Text APIs are used for +// OS Versions >= 10.6, ATSUI is used otherwise. class ComplexTextController { public: ComplexTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0); @@ -65,7 +70,8 @@ private: { return adoptRef(new ComplexTextRun(ctRun, fontData, characters, stringLocation, stringLength)); } -#elif USE(ATSUI) +#endif +#if USE(ATSUI) static PassRefPtr<ComplexTextRun> create(ATSUTextLayout atsuTextLayout, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride) { return adoptRef(new ComplexTextRun(atsuTextLayout, fontData, characters, stringLocation, stringLength, ltr, directionalOverride)); @@ -81,15 +87,18 @@ private: const UChar* characters() const { return m_characters; } unsigned stringLocation() const { return m_stringLocation; } size_t stringLength() const { return m_stringLength; } - CFIndex indexAt(size_t i) const { return m_indices[i]; } + ALWAYS_INLINE CFIndex indexAt(size_t i) const; const CGGlyph* glyphs() const { return m_glyphs; } const CGSize* advances() const { return m_advances; } private: #if USE(CORE_TEXT) ComplexTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength); -#elif USE(ATSUI) + void createTextRunFromFontDataCoreText(bool ltr); +#endif +#if USE(ATSUI) ComplexTextRun(ATSUTextLayout, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride); + void createTextRunFromFontDataATSUI(bool ltr); #endif ComplexTextRun(const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr); @@ -101,7 +110,7 @@ private: #endif #if USE(CORE_TEXT) - RetainPtr<CTRunRef> m_CTRun; + RetainPtr<CTRunRef> m_coreTextRun; #endif unsigned m_glyphCount; const SimpleFontData* m_fontData; @@ -109,10 +118,11 @@ private: unsigned m_stringLocation; size_t m_stringLength; #if USE(CORE_TEXT) - RetainPtr<CFMutableDataRef> m_indicesData; - const CFIndex* m_indices; -#elif USE(ATSUI) - Vector<CFIndex, 64> m_indices; + RetainPtr<CFMutableDataRef> m_coreTextIndicesData; + const CFIndex* m_coreTextIndices; +#endif +#if USE(ATSUI) + Vector<CFIndex, 64> m_atsuiIndices; #endif Vector<CGGlyph, 64> m_glyphsVector; const CGGlyph* m_glyphs; @@ -125,7 +135,12 @@ private: }; void collectComplexTextRuns(); + + // collectComplexTextRunsForCharacters() is a stub function that calls through to the ATSUI or Core Text variants based + // on the API in use. void collectComplexTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*); + void collectComplexTextRunsForCharactersATSUI(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*); + void collectComplexTextRunsForCharactersCoreText(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*); void adjustGlyphsAndAdvances(); const Font& m_font; diff --git a/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp b/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp index 78c588f..48aa174 100644 --- a/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp +++ b/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp @@ -45,7 +45,7 @@ OSStatus ComplexTextController::ComplexTextRun::overrideLayoutOperation(ATSULayo ComplexTextRun* complexTextRun = reinterpret_cast<ComplexTextRun*>(refCon); OSStatus status; ItemCount count; - ATSLayoutRecord *layoutRecords; + ATSLayoutRecord* layoutRecords; status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(atsuLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, reinterpret_cast<void**>(&layoutRecords), &count); if (status != noErr) { @@ -66,7 +66,7 @@ OSStatus ComplexTextController::ComplexTextRun::overrideLayoutOperation(ATSULayo complexTextRun->m_glyphCount = count; complexTextRun->m_glyphsVector.reserveCapacity(count); complexTextRun->m_advancesVector.reserveCapacity(count); - complexTextRun->m_indices.reserveCapacity(count); + complexTextRun->m_atsuiIndices.reserveCapacity(count); bool atBeginning = true; CGFloat lastX = 0; @@ -77,7 +77,7 @@ OSStatus ComplexTextController::ComplexTextRun::overrideLayoutOperation(ATSULayo continue; } complexTextRun->m_glyphsVector.uncheckedAppend(layoutRecords[j].glyphID); - complexTextRun->m_indices.uncheckedAppend(layoutRecords[j].originalOffset / 2 + indexOffset); + complexTextRun->m_atsuiIndices.uncheckedAppend(layoutRecords[j].originalOffset / 2 + indexOffset); CGFloat x = FixedToFloat(layoutRecords[j].realPos); if (!atBeginning) complexTextRun->m_advancesVector.uncheckedAppend(CGSizeMake(x - lastX, 0)); @@ -219,33 +219,29 @@ ComplexTextController::ComplexTextRun::ComplexTextRun(ATSUTextLayout atsuTextLay status = ATSUDisposeTextLayout(atsuTextLayout); } -ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) - : m_fontData(fontData) - , m_characters(characters) - , m_stringLocation(stringLocation) - , m_stringLength(stringLength) +void ComplexTextController::ComplexTextRun::createTextRunFromFontDataATSUI(bool ltr) { - m_indices.reserveCapacity(stringLength); + m_atsuiIndices.reserveCapacity(m_stringLength); unsigned r = 0; - while (r < stringLength) { - m_indices.uncheckedAppend(r); - if (U_IS_SURROGATE(characters[r])) { - ASSERT(r + 1 < stringLength); - ASSERT(U_IS_SURROGATE_LEAD(characters[r])); - ASSERT(U_IS_TRAIL(characters[r + 1])); + while (r < m_stringLength) { + m_atsuiIndices.uncheckedAppend(r); + if (U_IS_SURROGATE(m_characters[r])) { + ASSERT(r + 1 < m_stringLength); + ASSERT(U_IS_SURROGATE_LEAD(m_characters[r])); + ASSERT(U_IS_TRAIL(m_characters[r + 1])); r += 2; } else r++; } - m_glyphCount = m_indices.size(); + m_glyphCount = m_atsuiIndices.size(); if (!ltr) { for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end) - std::swap(m_indices[r], m_indices[end]); + std::swap(m_atsuiIndices[r], m_atsuiIndices[end]); } m_glyphsVector.fill(0, m_glyphCount); m_glyphs = m_glyphsVector.data(); - m_advancesVector.fill(CGSizeMake(fontData->widthForGlyph(0), 0), m_glyphCount); + m_advancesVector.fill(CGSizeMake(m_fontData->widthForGlyph(0), 0), m_glyphCount); m_advances = m_advancesVector.data(); } @@ -261,33 +257,37 @@ static bool fontHasMirroringInfo(ATSUFontID fontID) return false; } -static void disableLigatures(const SimpleFontData* fontData, TextRenderingMode textMode) +static void disableLigatures(const SimpleFontData* fontData, ATSUStyle atsuStyle, TypesettingFeatures typesettingFeatures) { // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example. // See bugzilla 5166. - if (textMode == OptimizeLegibility || textMode == GeometricPrecision || fontData->platformData().allowsLigatures()) + if ((typesettingFeatures & Ligatures) || fontData->platformData().allowsLigatures()) return; ATSUFontFeatureType featureTypes[] = { kLigaturesType }; ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector }; - OSStatus status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors); + OSStatus status = ATSUSetFontFeatures(atsuStyle, 1, featureTypes, featureSelectors); if (status != noErr) LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", static_cast<int>(status)); } -static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMode textMode) +static ATSUStyle initializeATSUStyle(const SimpleFontData* fontData, TypesettingFeatures typesettingFeatures) { - if (fontData->m_ATSUStyleInitialized) - return; + unsigned key = typesettingFeatures + 1; + pair<HashMap<unsigned, ATSUStyle>::iterator, bool> addResult = fontData->m_ATSUStyleMap.add(key, 0); + ATSUStyle& atsuStyle = addResult.first->second; + if (!addResult.second) + return atsuStyle; ATSUFontID fontID = fontData->platformData().m_atsuFontID; if (!fontID) { LOG_ERROR("unable to get ATSUFontID for %p", fontData->platformData().font()); - return; + fontData->m_ATSUStyleMap.remove(addResult.first); + return 0; } - OSStatus status = ATSUCreateStyle(&fontData->m_ATSUStyle); + OSStatus status = ATSUCreateStyle(&atsuStyle); if (status != noErr) LOG_ERROR("ATSUCreateStyle failed (%d)", static_cast<int>(status)); @@ -299,19 +299,18 @@ static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMod ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag }; ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &verticalFlip, &kerningInhibitFactor }; - bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision; - status = ATSUSetAttributes(fontData->m_ATSUStyle, allowKerning ? 3 : 4, styleTags, styleSizes, styleValues); + bool allowKerning = typesettingFeatures & Kerning; + status = ATSUSetAttributes(atsuStyle, allowKerning ? 3 : 4, styleTags, styleSizes, styleValues); if (status != noErr) LOG_ERROR("ATSUSetAttributes failed (%d)", static_cast<int>(status)); fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID); - disableLigatures(fontData, textMode); - - fontData->m_ATSUStyleInitialized = true; + disableLigatures(fontData, atsuStyle, typesettingFeatures); + return atsuStyle; } -void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) +void ComplexTextController::collectComplexTextRunsForCharactersATSUI(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) { if (!fontData) { // Create a run of missing glyphs from the primary font. @@ -322,13 +321,13 @@ void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, if (m_fallbackFonts && fontData != m_font.primaryFont()) m_fallbackFonts->add(fontData); - initializeATSUStyle(fontData, m_font.fontDescription().textRenderingMode()); + ATSUStyle atsuStyle = initializeATSUStyle(fontData, m_font.typesettingFeatures()); OSStatus status; ATSUTextLayout atsuTextLayout; UniCharCount runLength = length; - status = ATSUCreateTextLayoutWithTextPtr(cp, 0, length, length, 1, &runLength, &fontData->m_ATSUStyle, &atsuTextLayout); + status = ATSUCreateTextLayoutWithTextPtr(cp, 0, length, length, 1, &runLength, &atsuStyle, &atsuTextLayout); if (status != noErr) { LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed with error %d", static_cast<int>(status)); return; diff --git a/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp b/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp index c9daf84..dd5e96a 100644 --- a/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp +++ b/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp @@ -29,35 +29,44 @@ #include "Font.h" +#if defined(BUILDING_ON_LEOPARD) +// The following symbols are SPI in 10.5. +extern "C" { +void CTRunGetAdvances(CTRunRef run, CFRange range, CGSize buffer[]); +const CGSize* CTRunGetAdvancesPtr(CTRunRef run); +extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel; +} +#endif + namespace WebCore { ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength) - : m_CTRun(ctRun) + : m_coreTextRun(ctRun) , m_fontData(fontData) , m_characters(characters) , m_stringLocation(stringLocation) , m_stringLength(stringLength) { - m_glyphCount = CTRunGetGlyphCount(m_CTRun.get()); - m_indices = CTRunGetStringIndicesPtr(m_CTRun.get()); - if (!m_indices) { - m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); - CFDataIncreaseLength(m_indicesData.get(), m_glyphCount * sizeof(CFIndex)); - m_indices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_indicesData.get())); - CTRunGetStringIndices(m_CTRun.get(), CFRangeMake(0, 0), const_cast<CFIndex*>(m_indices)); + m_glyphCount = CTRunGetGlyphCount(m_coreTextRun.get()); + m_coreTextIndices = CTRunGetStringIndicesPtr(m_coreTextRun.get()); + if (!m_coreTextIndices) { + m_coreTextIndicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); + CFDataIncreaseLength(m_coreTextIndicesData.get(), m_glyphCount * sizeof(CFIndex)); + m_coreTextIndices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_coreTextIndicesData.get())); + CTRunGetStringIndices(m_coreTextRun.get(), CFRangeMake(0, 0), const_cast<CFIndex*>(m_coreTextIndices)); } - m_glyphs = CTRunGetGlyphsPtr(m_CTRun.get()); + m_glyphs = CTRunGetGlyphsPtr(m_coreTextRun.get()); if (!m_glyphs) { m_glyphsVector.grow(m_glyphCount); - CTRunGetGlyphs(m_CTRun.get(), CFRangeMake(0, 0), m_glyphsVector.data()); + CTRunGetGlyphs(m_coreTextRun.get(), CFRangeMake(0, 0), m_glyphsVector.data()); m_glyphs = m_glyphsVector.data(); } - m_advances = CTRunGetAdvancesPtr(m_CTRun.get()); + m_advances = CTRunGetAdvancesPtr(m_coreTextRun.get()); if (!m_advances) { m_advancesVector.grow(m_glyphCount); - CTRunGetAdvances(m_CTRun.get(), CFRangeMake(0, 0), m_advancesVector.data()); + CTRunGetAdvances(m_coreTextRun.get(), CFRangeMake(0, 0), m_advancesVector.data()); m_advances = m_advancesVector.data(); } @@ -65,20 +74,16 @@ ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const Simp // Missing glyphs run constructor. Core Text will not generate a run of missing glyphs, instead falling back on // glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path. -ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) - : m_fontData(fontData) - , m_characters(characters) - , m_stringLocation(stringLocation) - , m_stringLength(stringLength) +void ComplexTextController::ComplexTextRun::createTextRunFromFontDataCoreText(bool ltr) { Vector<CFIndex, 16> indices; unsigned r = 0; - while (r < stringLength) { + while (r < m_stringLength) { indices.append(r); - if (U_IS_SURROGATE(characters[r])) { - ASSERT(r + 1 < stringLength); - ASSERT(U_IS_SURROGATE_LEAD(characters[r])); - ASSERT(U_IS_TRAIL(characters[r + 1])); + if (U_IS_SURROGATE(m_characters[r])) { + ASSERT(r + 1 < m_stringLength); + ASSERT(U_IS_SURROGATE_LEAD(m_characters[r])); + ASSERT(U_IS_TRAIL(m_characters[r + 1])); r += 2; } else r++; @@ -88,9 +93,9 @@ ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* font for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end) std::swap(indices[r], indices[end]); } - m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); - CFDataAppendBytes(m_indicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex)); - m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get())); + m_coreTextIndicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); + CFDataAppendBytes(m_coreTextIndicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex)); + m_coreTextIndices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_coreTextIndicesData.get())); // Synthesize a run of missing glyphs. m_glyphsVector.fill(0, m_glyphCount); @@ -99,7 +104,7 @@ ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* font m_advances = m_advancesVector.data(); } -void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) +void ComplexTextController::collectComplexTextRunsForCharactersCoreText(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) { if (!fontData) { // Create a run of missing glyphs from the primary font. @@ -112,7 +117,7 @@ void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull)); - RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.fontDescription().textRenderingMode()))); + RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.typesettingFeatures()))); RetainPtr<CTTypesetterRef> typesetter; diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp index 41f63a9..5e5e1f4 100644 --- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp +++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp @@ -29,28 +29,24 @@ #include "GraphicsContext3D.h" -#include "CachedImage.h" +#include "CanvasObject.h" +#include "CString.h" +#include "ImageBuffer.h" +#include "NotImplemented.h" #include "WebGLActiveInfo.h" #include "WebGLArray.h" #include "WebGLBuffer.h" #include "WebGLFramebuffer.h" #include "WebGLFloatArray.h" #include "WebGLIntArray.h" -#include "CanvasObject.h" #include "WebGLProgram.h" #include "WebGLRenderbuffer.h" #include "WebGLShader.h" #include "WebGLTexture.h" #include "WebGLUnsignedByteArray.h" -#include "CString.h" -#include "HTMLCanvasElement.h" -#include "HTMLImageElement.h" -#include "ImageBuffer.h" -#include "NotImplemented.h" -#include "WebKitCSSMatrix.h" - #include <CoreGraphics/CGBitmapContext.h> #include <OpenGL/CGLRenderers.h> +#include <wtf/UnusedParam.h> namespace WebCore { @@ -79,18 +75,29 @@ static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBi attribs.append(static_cast<CGLPixelFormatAttribute>(0)); } -PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create() +PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs) { - OwnPtr<GraphicsContext3D> context(new GraphicsContext3D()); + OwnPtr<GraphicsContext3D> context(new GraphicsContext3D(attrs)); return context->m_contextObj ? context.release() : 0; } -GraphicsContext3D::GraphicsContext3D() - : m_contextObj(0) +GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs) + : m_attrs(attrs) + , m_contextObj(0) , m_texture(0) , m_fbo(0) , m_depthBuffer(0) { + // FIXME: we need to take into account the user's requested + // context creation attributes, in particular stencil and + // antialias, and determine which could and could not be honored + // based on the capabilities of the OpenGL implementation. + m_attrs.alpha = true; + m_attrs.depth = true; + m_attrs.stencil = false; + m_attrs.antialias = false; + m_attrs.premultipliedAlpha = true; + Vector<CGLPixelFormatAttribute> attribs; CGLPixelFormatObj pixelFormatObj = 0; GLint numPixelFormats = 0; @@ -262,7 +269,7 @@ void GraphicsContext3D::bindBuffer(unsigned long target, WebGLBuffer* buffer) void GraphicsContext3D::bindFramebuffer(unsigned long target, WebGLFramebuffer* buffer) { ensureContext(m_contextObj); - ::glBindFramebufferEXT(target, buffer ? (GLuint) buffer->object() : m_fbo); + ::glBindFramebufferEXT(target, (buffer && buffer->object()) ? (GLuint) buffer->object() : m_fbo); } void GraphicsContext3D::bindRenderbuffer(unsigned long target, WebGLRenderbuffer* renderbuffer) @@ -544,6 +551,11 @@ int GraphicsContext3D::getAttribLocation(WebGLProgram* program, const String& na return ::glGetAttribLocation((GLuint) program->object(), name.utf8().data()); } +GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes() +{ + return m_attrs; +} + unsigned long GraphicsContext3D::getError() { if (m_syntheticErrors.size() > 0) { @@ -1115,55 +1127,38 @@ long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long return reinterpret_cast<long>(pointer); } -// Assumes the texture you want to go into is bound -static void imageToTexture(Image* image, unsigned target, unsigned level) +// Returned pointer must be freed by fastFree() +static bool imageToTexture(Image* image, GLubyte*& buffer, size_t& width, size_t& height) { if (!image) - return; + return false; CGImageRef textureImage = image->getCGImageRef(); if (!textureImage) - return; + return false; - size_t textureWidth = CGImageGetWidth(textureImage); - size_t textureHeight = CGImageGetHeight(textureImage); + width = CGImageGetWidth(textureImage); + height = CGImageGetHeight(textureImage); - GLubyte* textureData = (GLubyte*) fastMalloc(textureWidth * textureHeight * 4); - if (!textureData) - return; + buffer = (GLubyte*) fastMalloc(width * height * 4); + if (!buffer) + return false; - CGContextRef textureContext = CGBitmapContextCreate(textureData, textureWidth, textureHeight, 8, textureWidth * 4, + CGContextRef textureContext = CGBitmapContextCreate(buffer, width, height, 8, width * 4, CGImageGetColorSpace(textureImage), kCGImageAlphaPremultipliedLast); CGContextSetBlendMode(textureContext, kCGBlendModeCopy); - CGContextDrawImage(textureContext, CGRectMake(0, 0, (CGFloat)textureWidth, (CGFloat)textureHeight), textureImage); + CGContextDrawImage(textureContext, CGRectMake(0, 0, (CGFloat)width, (CGFloat)height), textureImage); CGContextRelease(textureContext); - - ::glTexImage2D(target, level, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData); - fastFree(textureData); + return true; } -int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, WebGLArray* pixels) +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, void* pixels) { // FIXME: Need to do bounds checking on the buffer here. - ::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels->baseAddress()); + ::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); return 0; } -int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, ImageData* pixels) -{ - // FIXME: need to implement this form - UNUSED_PARAM(target); - UNUSED_PARAM(level); - UNUSED_PARAM(internalformat); - UNUSED_PARAM(width); - UNUSED_PARAM(height); - UNUSED_PARAM(border); - UNUSED_PARAM(format); - UNUSED_PARAM(type); - UNUSED_PARAM(pixels); - return -1; -} - int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha) { // FIXME: need to support flipY and premultiplyAlpha @@ -1172,85 +1167,43 @@ int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image, ASSERT(image); ensureContext(m_contextObj); - imageToTexture(image, target, level); + GLubyte* buffer; + size_t width; + size_t height; + if (!imageToTexture(image, buffer, width, height)) + return -1; + + ::glTexImage2D(target, level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + fastFree(buffer); return 0; } - -int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha) -{ - // FIXME: need to implement this form - UNUSED_PARAM(target); - UNUSED_PARAM(level); - UNUSED_PARAM(video); - - // FIXME: need to support flipY and premultiplyAlpha - UNUSED_PARAM(flipY); - UNUSED_PARAM(premultiplyAlpha); - return -1; -} - -int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, WebGLArray* pixels) -{ - // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size - UNUSED_PARAM(target); - UNUSED_PARAM(level); - UNUSED_PARAM(xoff); - UNUSED_PARAM(yoff); - UNUSED_PARAM(width); - UNUSED_PARAM(height); - UNUSED_PARAM(format); - UNUSED_PARAM(type); - UNUSED_PARAM(pixels); - return -1; -} - -int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, ImageData* pixels) -{ - // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size - UNUSED_PARAM(target); - UNUSED_PARAM(level); - UNUSED_PARAM(xoff); - UNUSED_PARAM(yoff); - UNUSED_PARAM(width); - UNUSED_PARAM(height); - UNUSED_PARAM(format); - UNUSED_PARAM(type); - UNUSED_PARAM(pixels); - return -1; -} - -int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, Image* image, bool flipY, bool premultiplyAlpha) + +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, void* pixels) { // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size - UNUSED_PARAM(target); - UNUSED_PARAM(level); - UNUSED_PARAM(xoff); - UNUSED_PARAM(yoff); - UNUSED_PARAM(width); - UNUSED_PARAM(height); - UNUSED_PARAM(image); - - // FIXME: need to support flipY and premultiplyAlpha - UNUSED_PARAM(flipY); - UNUSED_PARAM(premultiplyAlpha); - return -1; + // FIXME: Need to do bounds checking on the buffer here. + ::glTexSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels); + return 0; } -int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha) +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, Image* image, bool flipY, bool premultiplyAlpha) { // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size - UNUSED_PARAM(target); - UNUSED_PARAM(level); - UNUSED_PARAM(xoff); - UNUSED_PARAM(yoff); - UNUSED_PARAM(width); - UNUSED_PARAM(height); - UNUSED_PARAM(video); - - // FIXME: need to support flipY and premultiplyAlpha + // FIXME: need to support flipY and premultiplyAlpha UNUSED_PARAM(flipY); UNUSED_PARAM(premultiplyAlpha); - return -1; + ASSERT(image); + + ensureContext(m_contextObj); + GLubyte* buffer; + size_t width; + size_t height; + if (!imageToTexture(image, buffer, width, height)) + return -1; + + ::glTexSubImage2D(target, level, xoff, yoff, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + fastFree(buffer); + return 0; } unsigned GraphicsContext3D::createBuffer() diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm index 6c9b872..5f111f6 100644 --- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm +++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm @@ -26,7 +26,7 @@ #import "config.h" #import "GraphicsContext.h" -#import "../cg/GraphicsContextPlatformPrivateCG.h" +#import "GraphicsContextPlatformPrivateCG.h" #import <AppKit/AppKit.h> #import <wtf/StdLibExtras.h> @@ -43,33 +43,55 @@ namespace WebCore { // calls in this file are all exception-safe, so we don't block // exceptions for those. -void GraphicsContext::drawFocusRing(const Color& color) +static void drawFocusRingToContext(CGContextRef context, RetainPtr<CGPathRef> focusRingPath, RetainPtr<CGColorRef> colorRef, int radius) +{ +#ifdef BUILDING_ON_TIGER + CGContextBeginTransparencyLayer(context, 0); +#endif + CGContextBeginPath(context); + CGContextAddPath(context, focusRingPath.get()); + wkDrawFocusRing(context, colorRef.get(), radius); +#ifdef BUILDING_ON_TIGER + CGContextEndTransparencyLayer(context); +#endif +} + +void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color) +{ + if (paintingDisabled()) + return; + + int radius = (width - 1) / 2; + offset += radius; + RetainPtr<CGColorRef> colorRef; + if (color.isValid()) + colorRef.adoptCF(createCGColor(color)); + + RetainPtr<CGMutablePathRef> focusRingPath(AdoptCF, CGPathCreateMutable()); + unsigned pathCount = paths.size(); + for (unsigned i = 0; i < pathCount; i++) + CGPathAddPath(focusRingPath.get(), 0, paths[i].platformPath()); + + drawFocusRingToContext(platformContext(), focusRingPath, colorRef, radius); +} + +void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) { if (paintingDisabled()) return; - int radius = (focusRingWidth() - 1) / 2; - int offset = radius + focusRingOffset(); + int radius = (width - 1) / 2; + offset += radius; RetainPtr<CGColorRef> colorRef; if (color.isValid()) colorRef.adoptCF(createCGColor(color)); RetainPtr<CGMutablePathRef> focusRingPath(AdoptCF, CGPathCreateMutable()); - const Vector<IntRect>& rects = focusRingRects(); unsigned rectCount = rects.size(); for (unsigned i = 0; i < rectCount; i++) CGPathAddRect(focusRingPath.get(), 0, CGRectInset(rects[i], -offset, -offset)); - CGContextRef context = platformContext(); -#ifdef BUILDING_ON_TIGER - CGContextBeginTransparencyLayer(context, NULL); -#endif - CGContextBeginPath(context); - CGContextAddPath(context, focusRingPath.get()); - wkDrawFocusRing(context, colorRef.get(), radius); -#ifdef BUILDING_ON_TIGER - CGContextEndTransparencyLayer(context); -#endif + drawFocusRingToContext(platformContext(), focusRingPath, colorRef, radius); } #ifdef BUILDING_ON_TIGER // Post-Tiger's setCompositeOperation() is defined in GraphicsContextCG.cpp. diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h index 8024091..5362562 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h @@ -30,16 +30,16 @@ #include "GraphicsLayer.h" #include "StringHash.h" +#include "WebLayer.h" +#include <wtf/HashMap.h> #include <wtf/HashSet.h> #include <wtf/RetainPtr.h> @class CABasicAnimation; @class CAKeyframeAnimation; -@class CALayer; @class CAMediaTimingFunction; @class CAPropertyAnimation; @class WebAnimationDelegate; -@class WebLayer; namespace WebCore { @@ -64,6 +64,7 @@ public: virtual void removeFromParent(); virtual void setMaskLayer(GraphicsLayer*); + virtual void setReplicatedLayer(GraphicsLayer*); virtual void setPosition(const FloatPoint&); virtual void setAnchorPoint(const FloatPoint3D&); @@ -98,13 +99,13 @@ public: virtual void suspendAnimations(double time); virtual void resumeAnimations(); - virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& keyframesName, double beginTime); + virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& keyframesName, double timeOffset); virtual void removeAnimationsForProperty(AnimatedPropertyID); virtual void removeAnimationsForKeyframes(const String& keyframesName); - virtual void pauseAnimation(const String& keyframesName); + virtual void pauseAnimation(const String& keyframesName, double timeOffset); virtual void setContentsToImage(Image*); - virtual void setContentsToVideo(PlatformLayer*); + virtual void setContentsToMedia(PlatformLayer*); #if ENABLE(3D_CANVAS) virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*); #endif @@ -116,8 +117,9 @@ public: virtual void setGeometryOrientation(CompositingCoordinatesOrientation); + virtual void didDisplay(PlatformLayer*); + void recursiveCommitChanges(); - void commitLayerChanges(); virtual void syncCompositingState(); @@ -127,13 +129,20 @@ protected: private: void updateOpacityOnLayer(); - WebLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); } - WebLayer* hostLayerForSublayers() const; - WebLayer* layerForSuperlayer() const; + CALayer* primaryLayer() const { return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get(); } + CALayer* hostLayerForSublayers() const; + CALayer* layerForSuperlayer() const; CALayer* animatedLayer(AnimatedPropertyID property) const; - bool createAnimationFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double beginTime); - bool createTransformAnimationsFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double beginTime, const IntSize& boxSize); + typedef String CloneID; // Identifier for a given clone, based on original/replica branching down the tree. + static bool isReplicatedRootClone(const CloneID& cloneID) { return cloneID[0U] & 1; } + + typedef HashMap<CloneID, RetainPtr<CALayer> > LayerMap; + LayerMap* primaryLayerClones() const { return m_structuralLayer.get() ? m_structuralLayerClones.get() : m_layerClones.get(); } + LayerMap* animatedLayerClones(AnimatedPropertyID property) const; + + bool createAnimationFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double timeOffset); + bool createTransformAnimationsFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double timeOffset, const IntSize& boxSize); // Return autoreleased animation (use RetainPtr?) CABasicAnimation* createBasicAnimation(const Animation*, AnimatedPropertyID, bool additive); @@ -153,6 +162,9 @@ private: return m_runningKeyframeAnimations.find(keyframesName) != m_runningKeyframeAnimations.end(); } + void commitLayerChangesBeforeSublayers(); + void commitLayerChangesAfterSublayers(); + bool requiresTiledLayer(const FloatSize&) const; void swapFromOrToTiledLayer(bool useTiledLayer); @@ -161,8 +173,75 @@ private: void setupContentsLayer(CALayer*); CALayer* contentsLayer() const { return m_contentsLayer.get(); } + + virtual void setReplicatedByLayer(GraphicsLayer*); + + // Used to track the path down the tree for replica layers. + struct ReplicaState { + static const size_t maxReplicaDepth = 16; + enum ReplicaBranchType { ChildBranch = 0, ReplicaBranch = 1 }; + ReplicaState(ReplicaBranchType firstBranch) + : m_replicaDepth(0) + { + push(firstBranch); + } + + // Called as we walk down the tree to build replicas. + void push(ReplicaBranchType branchType) + { + m_replicaBranches.append(branchType); + if (branchType == ReplicaBranch) + ++m_replicaDepth; + } + + void setBranchType(ReplicaBranchType branchType) + { + ASSERT(!m_replicaBranches.isEmpty()); + + if (m_replicaBranches.last() != branchType) { + if (branchType == ReplicaBranch) + ++m_replicaDepth; + else + --m_replicaDepth; + } + + m_replicaBranches.last() = branchType; + } + + void pop() + { + if (m_replicaBranches.last() == ReplicaBranch) + --m_replicaDepth; + m_replicaBranches.removeLast(); + } + + size_t depth() const { return m_replicaBranches.size(); } + size_t replicaDepth() const { return m_replicaDepth; } + + CloneID cloneID() const; + + private: + Vector<ReplicaBranchType> m_replicaBranches; + size_t m_replicaDepth; + }; + CALayer *replicatedLayerRoot(ReplicaState&); + + enum CloneLevel { RootCloneLevel, IntermediateCloneLevel }; + CALayer *fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState&, CloneLevel); + + CALayer *cloneLayer(CALayer *, CloneLevel); + CALayer *findOrMakeClone(CloneID, CALayer *, LayerMap*, CloneLevel); + + void ensureCloneLayers(CloneID index, CALayer *& primaryLayer, CALayer *& structuralLayer, CALayer *& contentsLayer, CloneLevel); + + bool hasCloneLayers() const { return m_layerClones; } + void removeCloneLayers(); + FloatPoint positionForCloneRootLayer() const; + + void propagateLayerChangeToReplicas(); // All these "update" methods will be called inside a BEGIN_BLOCK_OBJC_EXCEPTIONS/END_BLOCK_OBJC_EXCEPTIONS block. + void updateLayerNames(); void updateSublayerList(); void updateLayerPosition(); void updateLayerSize(); @@ -172,25 +251,38 @@ private: void updateMasksToBounds(); void updateContentsOpaque(); void updateBackfaceVisibility(); - void updateLayerPreserves3D(); + void updateStructuralLayer(); void updateLayerDrawsContent(); void updateLayerBackgroundColor(); void updateContentsImage(); - void updateContentsVideo(); + void updateContentsMediaLayer(); #if ENABLE(3D_CANVAS) void updateContentsGraphicsContext3D(); #endif void updateContentsRect(); void updateGeometryOrientation(); void updateMaskLayer(); + void updateReplicatedLayers(); void updateLayerAnimations(); + + enum StructuralLayerPurpose { + NoStructuralLayer = 0, + StructuralLayerForPreserves3D, + StructuralLayerForReplicaFlattening + }; + void ensureStructuralLayer(StructuralLayerPurpose); + StructuralLayerPurpose structuralLayerPurpose() const; - void setAnimationOnLayer(CAPropertyAnimation*, AnimatedPropertyID, int index, double beginTime); - bool removeAnimationFromLayer(AnimatedPropertyID, int index); - void pauseAnimationOnLayer(AnimatedPropertyID, int index); + void setAnimationOnLayer(CAPropertyAnimation*, AnimatedPropertyID, const String& keyframesName, int index, double timeOffset); + bool removeAnimationFromLayer(AnimatedPropertyID, const String& keyframesName, int index); + void pauseAnimationOnLayer(AnimatedPropertyID, const String& keyframesName, int index, double timeOffset); + enum MoveOrCopy { Move, Copy }; + void moveOrCopyAnimationsForProperty(MoveOrCopy, AnimatedPropertyID property, CALayer * fromLayer, CALayer * toLayer); + static void moveOrCopyAllAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, const String& keyframesName, CALayer * fromLayer, CALayer * toLayer); + enum LayerChange { NoChange = 0, NameChanged = 1 << 1, @@ -210,27 +302,34 @@ private: AnimationChanged = 1 << 15, DirtyRectsChanged = 1 << 16, ContentsImageChanged = 1 << 17, - ContentsVideoChanged = 1 << 18, + ContentsMediaLayerChanged = 1 << 18, #if ENABLE(3D_CANVAS) ContentsGraphicsContext3DChanged = 1 << 19, #endif ContentsRectChanged = 1 << 20, GeometryOrientationChanged = 1 << 21, - MaskLayerChanged = 1 << 22 + MaskLayerChanged = 1 << 22, + ReplicatedLayerChanged = 1 << 23 }; typedef unsigned LayerChangeFlags; void noteLayerPropertyChanged(LayerChangeFlags flags); + void noteSublayersChanged(); void repaintLayerDirtyRects(); - RetainPtr<WebLayer> m_layer; - RetainPtr<WebLayer> m_transformLayer; - RetainPtr<CALayer> m_contentsLayer; + RetainPtr<WebLayer> m_layer; // The main layer + RetainPtr<CALayer> m_structuralLayer; // A layer used for structural reasons, like preserves-3d or replica-flattening. Is the parent of m_layer. + RetainPtr<CALayer> m_contentsLayer; // A layer used for inner content, like image and video + + // References to clones of our layers, for replicated layers. + OwnPtr<LayerMap> m_layerClones; + OwnPtr<LayerMap> m_structuralLayerClones; + OwnPtr<LayerMap> m_contentsLayerClones; enum ContentsLayerPurpose { NoContentsLayer = 0, ContentsLayerForImage, - ContentsLayerForVideo + ContentsLayerForMedia #if ENABLE(3D_CANVAS) ,ContentsLayerForGraphicsLayer3D #endif @@ -244,19 +343,19 @@ private: RetainPtr<CGImageRef> m_pendingContentsImage; struct LayerAnimation { - LayerAnimation(CAPropertyAnimation* caAnim, const String& keyframesName, AnimatedPropertyID property, int index, double beginTime) + LayerAnimation(CAPropertyAnimation* caAnim, const String& keyframesName, AnimatedPropertyID property, int index, double timeOffset) : m_animation(caAnim) , m_keyframesName(keyframesName) , m_property(property) , m_index(index) - , m_beginTime(beginTime) + , m_timeOffset(timeOffset) { } RetainPtr<CAPropertyAnimation*> m_animation; String m_keyframesName; AnimatedPropertyID m_property; int m_index; - double m_beginTime; + double m_timeOffset; }; Vector<LayerAnimation> m_uncomittedAnimations; @@ -267,8 +366,16 @@ private: HashSet<AnimatedProperty> m_transitionPropertiesToRemove; - enum { Remove, Pause }; - typedef int AnimationProcessingAction; + enum Action { Remove, Pause }; + struct AnimationProcessingAction { + AnimationProcessingAction(Action action = Remove, double timeOffset = 0) + : action(action) + , timeOffset(timeOffset) + { + } + Action action; + double timeOffset; // only used for pause + }; typedef HashMap<String, AnimationProcessingAction> AnimationsToProcessMap; AnimationsToProcessMap m_keyframeAnimationsToProcess; diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index dea6bfc..22e39f5 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -42,6 +42,7 @@ #import <QuartzCore/QuartzCore.h> #import "RotateTransformOperation.h" #import "ScaleTransformOperation.h" +#import "StringBuilder.h" #import "SystemTime.h" #import "TranslateTransformOperation.h" #import "WebLayer.h" @@ -86,6 +87,10 @@ static double mediaTimeToCurrentTime(CFTimeInterval t) } // namespace WebCore +@interface CALayer(Private) +- (void)setContentsChanged; +@end + @interface WebAnimationDelegate : NSObject { WebCore::GraphicsLayerCA* m_graphicsLayer; } @@ -246,12 +251,20 @@ static String propertyIdToString(AnimatedPropertyID property) return ""; } -static String animationIdentifier(AnimatedPropertyID property, int index) +static String animationIdentifier(AnimatedPropertyID property, const String& keyframesName, int index) { - String animationId = propertyIdToString(property); - animationId.append("_"); - animationId.append(String::number(index)); - return animationId; + StringBuilder builder; + + builder.append(propertyIdToString(property)); + builder.append("_"); + + if (!keyframesName.isEmpty()) { + builder.append(keyframesName); + builder.append("_"); + } + builder.append("_"); + builder.append(String::number(index)); + return builder.toString(); } #if !HAVE_MODERN_QUARTZCORE @@ -392,9 +405,17 @@ GraphicsLayerCA::~GraphicsLayerCA() [layer setLayerOwner:nil]; } + if (m_contentsLayer) { + if ([m_contentsLayer.get() respondsToSelector:@selector(setLayerOwner:)]) + [(id)m_contentsLayer.get() setLayerOwner:nil]; + } + // animationDidStart: can fire after this, so we need to clear out the layer on the delegate. [m_animationDelegate.get() setLayer:0]; + // Release the clone layers inside the exception-handling block. + removeCloneLayers(); + END_BLOCK_OBJC_EXCEPTIONS } @@ -414,7 +435,7 @@ bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children) { bool childrenChanged = GraphicsLayer::setChildren(children); if (childrenChanged) - noteLayerPropertyChanged(ChildrenChanged); + noteSublayersChanged(); return childrenChanged; } @@ -422,31 +443,31 @@ bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children) void GraphicsLayerCA::addChild(GraphicsLayer* childLayer) { GraphicsLayer::addChild(childLayer); - noteLayerPropertyChanged(ChildrenChanged); + noteSublayersChanged(); } void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index) { GraphicsLayer::addChildAtIndex(childLayer, index); - noteLayerPropertyChanged(ChildrenChanged); + noteSublayersChanged(); } void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling) { GraphicsLayer::addChildBelow(childLayer, sibling); - noteLayerPropertyChanged(ChildrenChanged); + noteSublayersChanged(); } void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling) { GraphicsLayer::addChildAbove(childLayer, sibling); - noteLayerPropertyChanged(ChildrenChanged); + noteSublayersChanged(); } bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) { if (GraphicsLayer::replaceChild(oldChild, newChild)) { - noteLayerPropertyChanged(ChildrenChanged); + noteSublayersChanged(); return true; } return false; @@ -455,7 +476,7 @@ bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newCh void GraphicsLayerCA::removeFromParent() { if (m_parent) - static_cast<GraphicsLayerCA*>(m_parent)->noteLayerPropertyChanged(ChildrenChanged); + static_cast<GraphicsLayerCA*>(m_parent)->noteSublayersChanged(); GraphicsLayer::removeFromParent(); } @@ -466,6 +487,30 @@ void GraphicsLayerCA::setMaskLayer(GraphicsLayer* layer) GraphicsLayer::setMaskLayer(layer); noteLayerPropertyChanged(MaskLayerChanged); + + propagateLayerChangeToReplicas(); + + if (m_replicatedLayer) + static_cast<GraphicsLayerCA*>(m_replicatedLayer)->propagateLayerChangeToReplicas(); +} + +void GraphicsLayerCA::setReplicatedLayer(GraphicsLayer* layer) +{ + if (layer == m_replicatedLayer) + return; + + GraphicsLayer::setReplicatedLayer(layer); + noteLayerPropertyChanged(ReplicatedLayerChanged); +} + +void GraphicsLayerCA::setReplicatedByLayer(GraphicsLayer* layer) +{ + if (layer == m_replicaLayer) + return; + + GraphicsLayer::setReplicatedByLayer(layer); + noteSublayersChanged(); + noteLayerPropertyChanged(ReplicatedLayerChanged); } void GraphicsLayerCA::setPosition(const FloatPoint& point) @@ -513,22 +558,41 @@ void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t) noteLayerPropertyChanged(ChildrenTransformChanged); } -static void moveAnimation(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer) +void GraphicsLayerCA::moveOrCopyAllAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, const String& keyframesName, CALayer *fromLayer, CALayer *toLayer) { for (int index = 0; ; ++index) { - String animName = animationIdentifier(property, index); + String animName = animationIdentifier(property, keyframesName, index); CAAnimation* anim = [fromLayer animationForKey:animName]; if (!anim) break; - [anim retain]; - [fromLayer removeAnimationForKey:animName]; - [toLayer addAnimation:anim forKey:animName]; - [anim release]; + switch (operation) { + case Move: + [anim retain]; + [fromLayer removeAnimationForKey:animName]; + [toLayer addAnimation:anim forKey:animName]; + [anim release]; + break; + + case Copy: + [toLayer addAnimation:anim forKey:animName]; + break; + } } } +void GraphicsLayerCA::moveOrCopyAnimationsForProperty(MoveOrCopy operation, AnimatedPropertyID property, CALayer *fromLayer, CALayer *toLayer) +{ + // Move transitions for this property. + moveOrCopyAllAnimationsForProperty(operation, property, "", fromLayer, toLayer); + + // Look for running animations affecting this property. + KeyframeAnimationsMap::const_iterator end = m_runningKeyframeAnimations.end(); + for (KeyframeAnimationsMap::const_iterator it = m_runningKeyframeAnimations.begin(); it != end; ++it) + moveOrCopyAllAnimationsForProperty(operation, property, it->first, fromLayer, toLayer); +} + void GraphicsLayerCA::setPreserves3D(bool preserves3D) { if (preserves3D == m_preserves3D) @@ -643,7 +707,7 @@ void GraphicsLayerCA::setContentsRect(const IntRect& rect) noteLayerPropertyChanged(ContentsRectChanged); } -bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double beginTime) +bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset) { if (forceSoftwareAnimation() || !anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2) return false; @@ -657,9 +721,9 @@ bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const Int bool createdAnimations = false; if (valueList.property() == AnimatedPropertyWebkitTransform) - createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, keyframesName, beginTime, boxSize); + createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, keyframesName, timeOffset, boxSize); else - createdAnimations = createAnimationFromKeyframes(valueList, anim, keyframesName, beginTime); + createdAnimations = createAnimationFromKeyframes(valueList, anim, keyframesName, timeOffset); if (createdAnimations) noteLayerPropertyChanged(AnimationChanged); @@ -681,22 +745,23 @@ void GraphicsLayerCA::removeAnimationsForKeyframes(const String& animationName) if (!animationIsRunning(animationName)) return; - m_keyframeAnimationsToProcess.add(animationName, Remove); + m_keyframeAnimationsToProcess.add(animationName, AnimationProcessingAction(Remove)); noteLayerPropertyChanged(AnimationChanged); } -void GraphicsLayerCA::pauseAnimation(const String& keyframesName) +void GraphicsLayerCA::pauseAnimation(const String& keyframesName, double timeOffset) { if (!animationIsRunning(keyframesName)) return; AnimationsToProcessMap::iterator it = m_keyframeAnimationsToProcess.find(keyframesName); if (it != m_keyframeAnimationsToProcess.end()) { + AnimationProcessingAction& processingInfo = it->second; // If an animation is scheduled to be removed, don't change the remove to a pause. - if (it->second != Remove) - it->second = Pause; + if (processingInfo.action != Remove) + processingInfo.action = Pause; } else - m_keyframeAnimationsToProcess.add(keyframesName, Pause); + m_keyframeAnimationsToProcess.add(keyframesName, AnimationProcessingAction(Pause, timeOffset)); noteLayerPropertyChanged(AnimationChanged); } @@ -716,26 +781,27 @@ void GraphicsLayerCA::setContentsToImage(Image* image) } m_contentsLayerPurpose = ContentsLayerForImage; if (!m_contentsLayer) - noteLayerPropertyChanged(ChildrenChanged); + noteSublayersChanged(); } else { m_pendingContentsImage = 0; m_contentsLayerPurpose = NoContentsLayer; if (m_contentsLayer) - noteLayerPropertyChanged(ChildrenChanged); + noteSublayersChanged(); } noteLayerPropertyChanged(ContentsImageChanged); } -void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer) +void GraphicsLayerCA::setContentsToMedia(PlatformLayer* mediaLayer) { - if (videoLayer != m_contentsLayer.get()) - noteLayerPropertyChanged(ChildrenChanged); + if (mediaLayer == m_contentsLayer) + return; - m_contentsLayer = videoLayer; - noteLayerPropertyChanged(ContentsVideoChanged); + m_contentsLayer = mediaLayer; + m_contentsLayerPurpose = mediaLayer ? ContentsLayerForMedia : NoContentsLayer; - m_contentsLayerPurpose = videoLayer ? ContentsLayerForVideo : NoContentsLayer; + noteSublayersChanged(); + noteLayerPropertyChanged(ContentsMediaLayerChanged); } void GraphicsLayerCA::setGeometryOrientation(CompositingCoordinatesOrientation orientation) @@ -760,6 +826,35 @@ void GraphicsLayerCA::setGeometryOrientation(CompositingCoordinatesOrientation o #endif } +void GraphicsLayerCA::didDisplay(PlatformLayer* layer) +{ + CALayer* sourceLayer; + LayerMap* layerCloneMap; + + if (layer == m_layer) { + sourceLayer = m_layer.get(); + layerCloneMap = m_layerClones.get(); + } else if (layer == m_contentsLayer) { + sourceLayer = m_contentsLayer.get(); + layerCloneMap = m_contentsLayerClones.get(); + } else + return; + + if (layerCloneMap) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + CALayer *currClone = it->second.get(); + if (!currClone) + continue; + + if ([currClone contents] != [sourceLayer contents]) + [currClone setContents:[sourceLayer contents]]; + else + [currClone setContentsChanged]; + } + } +} + void GraphicsLayerCA::syncCompositingState() { recursiveCommitChanges(); @@ -767,10 +862,10 @@ void GraphicsLayerCA::syncCompositingState() void GraphicsLayerCA::recursiveCommitChanges() { - commitLayerChanges(); + commitLayerChangesBeforeSublayers(); if (m_maskLayer) - static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChanges(); + static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChangesBeforeSublayers(); const Vector<GraphicsLayer*>& childLayers = children(); size_t numChildren = childLayers.size(); @@ -778,9 +873,17 @@ void GraphicsLayerCA::recursiveCommitChanges() GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]); curChild->recursiveCommitChanges(); } + + if (m_replicaLayer) + static_cast<GraphicsLayerCA*>(m_replicaLayer)->recursiveCommitChanges(); + + if (m_maskLayer) + static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChangesAfterSublayers(); + + commitLayerChangesAfterSublayers(); } -void GraphicsLayerCA::commitLayerChanges() +void GraphicsLayerCA::commitLayerChangesBeforeSublayers() { if (!m_uncommittedChanges) return; @@ -788,20 +891,17 @@ void GraphicsLayerCA::commitLayerChanges() BEGIN_BLOCK_OBJC_EXCEPTIONS // Need to handle Preserves3DChanged first, because it affects which layers subsequent properties are applied to - if (m_uncommittedChanges & Preserves3DChanged) - updateLayerPreserves3D(); + if (m_uncommittedChanges & (Preserves3DChanged | ReplicatedLayerChanged)) + updateStructuralLayer(); - if (m_uncommittedChanges & NameChanged) { - if (m_transformLayer) - [m_transformLayer.get() setName:("Transform layer " + name())]; - [m_layer.get() setName:name()]; - } + if (m_uncommittedChanges & NameChanged) + updateLayerNames(); if (m_uncommittedChanges & ContentsImageChanged) // Needs to happen before ChildrenChanged updateContentsImage(); - if (m_uncommittedChanges & ContentsVideoChanged) // Needs to happen before ChildrenChanged - updateContentsVideo(); + if (m_uncommittedChanges & ContentsMediaLayerChanged) // Needs to happen before ChildrenChanged + updateContentsMediaLayer(); #if ENABLE(3D_CANVAS) if (m_uncommittedChanges & ContentsGraphicsContext3DChanged) // Needs to happen before ChildrenChanged @@ -859,40 +959,72 @@ void GraphicsLayerCA::commitLayerChanges() if (m_uncommittedChanges & MaskLayerChanged) updateMaskLayer(); + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::commitLayerChangesAfterSublayers() +{ + if (!m_uncommittedChanges) + return; + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + if (m_uncommittedChanges & ReplicatedLayerChanged) + updateReplicatedLayers(); + m_uncommittedChanges = NoChange; END_BLOCK_OBJC_EXCEPTIONS } +void GraphicsLayerCA::updateLayerNames() +{ + switch (structuralLayerPurpose()) { + case StructuralLayerForPreserves3D: + [m_structuralLayer.get() setName:("Transform layer " + name())]; + break; + case StructuralLayerForReplicaFlattening: + [m_structuralLayer.get() setName:("Replica flattening layer " + name())]; + break; + case NoStructuralLayer: + break; + } + [m_layer.get() setName:name()]; +} + void GraphicsLayerCA::updateSublayerList() { NSMutableArray* newSublayers = nil; - if (m_transformLayer) { - // Add the primary layer first. Even if we have negative z-order children, the primary layer always comes behind. - newSublayers = [[NSMutableArray alloc] initWithObjects:m_layer.get(), nil]; - } else if (m_contentsLayer) { - // FIXME: add the contents layer in the correct order with negative z-order children. - // This does not cause visible rendering issues because currently contents layers are only used - // for replaced elements that don't have children. - newSublayers = [[NSMutableArray alloc] initWithObjects:m_contentsLayer.get(), nil]; - } - const Vector<GraphicsLayer*>& childLayers = children(); - size_t numChildren = childLayers.size(); - for (size_t i = 0; i < numChildren; ++i) { - GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]); - - CALayer* childLayer = curChild->layerForSuperlayer(); - if (!newSublayers) - newSublayers = [[NSMutableArray alloc] initWithObjects:childLayer, nil]; - else + + if (m_structuralLayer || m_contentsLayer || childLayers.size() > 0) { + newSublayers = [[NSMutableArray alloc] init]; + + if (m_structuralLayer) { + // Add the replica layer first. + if (m_replicaLayer) + [newSublayers addObject:static_cast<GraphicsLayerCA*>(m_replicaLayer)->primaryLayer()]; + // Add the primary layer. Even if we have negative z-order children, the primary layer always comes behind. + [newSublayers addObject:m_layer.get()]; + } else if (m_contentsLayer) { + // FIXME: add the contents layer in the correct order with negative z-order children. + // This does not cause visible rendering issues because currently contents layers are only used + // for replaced elements that don't have children. + [newSublayers addObject:m_contentsLayer.get()]; + } + + size_t numChildren = childLayers.size(); + for (size_t i = 0; i < numChildren; ++i) { + GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]); + CALayer *childLayer = curChild->layerForSuperlayer(); [newSublayers addObject:childLayer]; - } + } - [newSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]; + [newSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]; + } - if (m_transformLayer) { - safeSetSublayers(m_transformLayer.get(), newSublayers); + if (m_structuralLayer) { + safeSetSublayers(m_structuralLayer.get(), newSublayers); if (m_contentsLayer) { // If we have a transform layer, then the contents layer is parented in the @@ -913,16 +1045,43 @@ void GraphicsLayerCA::updateLayerPosition() m_position.y() + m_anchorPoint.y() * m_size.height()); [primaryLayer() setPosition:posPoint]; + + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + CGPoint clonePosition = posPoint; + if (m_replicaLayer && isReplicatedRootClone(it->first)) { + // Maintain the special-case position for the root of a clone subtree, + // which we set up in replicatedLayerRoot(). + clonePosition = positionForCloneRootLayer(); + } + CALayer *currLayer = it->second.get(); + [currLayer setPosition:clonePosition]; + } + } } void GraphicsLayerCA::updateLayerSize() { CGRect rect = CGRectMake(0, 0, m_size.width(), m_size.height()); - if (m_transformLayer) { - [m_transformLayer.get() setBounds:rect]; + if (m_structuralLayer) { + [m_structuralLayer.get() setBounds:rect]; + + if (LayerMap* layerCloneMap = m_structuralLayerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) + [it->second.get() setBounds:rect]; + } + // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative. CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); [m_layer.get() setPosition:centerPoint]; + + if (LayerMap* layerCloneMap = m_layerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) + [it->second.get() setPosition:centerPoint]; + } } bool needTiledLayer = requiresTiledLayer(m_size); @@ -930,6 +1089,11 @@ void GraphicsLayerCA::updateLayerSize() swapFromOrToTiledLayer(needTiledLayer); [m_layer.get() setBounds:rect]; + if (LayerMap* layerCloneMap = m_layerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) + [it->second.get() setBounds:rect]; + } // Contents transform may depend on height. updateContentsTransform(); @@ -947,6 +1111,18 @@ void GraphicsLayerCA::updateAnchorPoint() #if HAVE_MODERN_QUARTZCORE [primaryLayer() setAnchorPointZ:m_anchorPoint.z()]; #endif + + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + CALayer *currLayer = it->second.get(); + [currLayer setAnchorPoint:FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())]; +#if HAVE_MODERN_QUARTZCORE + [currLayer setAnchorPointZ:m_anchorPoint.z()]; +#endif + } + } + updateLayerPosition(); } @@ -955,6 +1131,19 @@ void GraphicsLayerCA::updateTransform() CATransform3D transform; copyTransform(transform, m_transform); [primaryLayer() setTransform:transform]; + + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + CALayer *currLayer = it->second.get(); + if (m_replicaLayer && isReplicatedRootClone(it->first)) { + // Maintain the special-case transform for the root of a clone subtree, + // which we set up in replicatedLayerRoot(). + [currLayer setTransform:CATransform3DIdentity]; + } else + [currLayer setTransform:transform]; + } + } } void GraphicsLayerCA::updateChildrenTransform() @@ -962,85 +1151,157 @@ void GraphicsLayerCA::updateChildrenTransform() CATransform3D transform; copyTransform(transform, m_childrenTransform); [primaryLayer() setSublayerTransform:transform]; + + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + CALayer *currLayer = it->second.get(); + [currLayer setSublayerTransform:transform]; + } + } } void GraphicsLayerCA::updateMasksToBounds() { [m_layer.get() setMasksToBounds:m_masksToBounds]; + + if (LayerMap* layerCloneMap = m_layerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + CALayer *currLayer = it->second.get(); + [currLayer setMasksToBounds:m_masksToBounds]; + } + } + updateDebugIndicators(); } void GraphicsLayerCA::updateContentsOpaque() { [m_layer.get() setOpaque:m_contentsOpaque]; + + if (LayerMap* layerCloneMap = m_layerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + CALayer *currLayer = it->second.get(); + [currLayer setOpaque:m_contentsOpaque]; + } + } } void GraphicsLayerCA::updateBackfaceVisibility() { [m_layer.get() setDoubleSided:m_backfaceVisibility]; + + if (LayerMap* layerCloneMap = m_layerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + CALayer *currLayer = it->second.get(); + [currLayer setDoubleSided:m_backfaceVisibility]; + } + } } -void GraphicsLayerCA::updateLayerPreserves3D() +void GraphicsLayerCA::updateStructuralLayer() { - Class transformLayerClass = NSClassFromString(@"CATransformLayer"); - if (!transformLayerClass) - return; + ensureStructuralLayer(structuralLayerPurpose()); +} - if (m_preserves3D && !m_transformLayer) { - // Create the transform layer. - m_transformLayer.adoptNS([[transformLayerClass alloc] init]); +void GraphicsLayerCA::ensureStructuralLayer(StructuralLayerPurpose purpose) +{ + if (purpose == NoStructuralLayer) { + if (m_structuralLayer) { + // Replace the transformLayer in the parent with this layer. + [m_layer.get() removeFromSuperlayer]; + [[m_structuralLayer.get() superlayer] replaceSublayer:m_structuralLayer.get() with:m_layer.get()]; - // Turn off default animations. - [m_transformLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]]; + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_structuralLayer.get(), m_layer.get()); + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_structuralLayer.get(), m_layer.get()); -#ifndef NDEBUG - [m_transformLayer.get() setName:[NSString stringWithFormat:@"Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this]]; -#endif - // Copy the position from this layer. - updateLayerPosition(); - updateLayerSize(); - updateAnchorPoint(); - updateTransform(); - updateChildrenTransform(); - - CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); - [m_layer.get() setPosition:point]; + // Release the structural layer. + m_structuralLayer = 0; - [m_layer.get() setAnchorPoint:CGPointMake(0.5f, 0.5f)]; - [m_layer.get() setTransform:CATransform3DIdentity]; - - // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer. - [m_layer.get() setOpacity:1]; + // Update the properties of m_layer now that we no loner have a structural layer. + updateLayerPosition(); + updateLayerSize(); + updateAnchorPoint(); + updateTransform(); + updateChildrenTransform(); - // Move this layer to be a child of the transform layer. - [[m_layer.get() superlayer] replaceSublayer:m_layer.get() with:m_transformLayer.get()]; - [m_transformLayer.get() addSublayer:m_layer.get()]; + updateSublayerList(); + updateOpacityOnLayer(); + } + return; + } + + bool structuralLayerChanged = false; + + if (purpose == StructuralLayerForPreserves3D) { + Class transformLayerClass = NSClassFromString(@"CATransformLayer"); + if (!transformLayerClass) + return; - moveAnimation(AnimatedPropertyWebkitTransform, m_layer.get(), m_transformLayer.get()); + if (m_structuralLayer && ![m_structuralLayer.get() isKindOfClass:transformLayerClass]) + m_structuralLayer = 0; - updateSublayerList(); - } else if (!m_preserves3D && m_transformLayer) { - // Relace the transformLayer in the parent with this layer. - [m_layer.get() removeFromSuperlayer]; - [[m_transformLayer.get() superlayer] replaceSublayer:m_transformLayer.get() with:m_layer.get()]; - - moveAnimation(AnimatedPropertyWebkitTransform, m_transformLayer.get(), m_layer.get()); - - // Release the transform layer. - m_transformLayer = 0; - - updateLayerPosition(); - updateLayerSize(); - updateAnchorPoint(); - updateTransform(); - updateChildrenTransform(); + if (!m_structuralLayer) { + m_structuralLayer.adoptNS([[transformLayerClass alloc] init]); + structuralLayerChanged = true; + } + } else { + if (m_structuralLayer && ![m_structuralLayer.get() isMemberOfClass:[CALayer self]]) + m_structuralLayer = 0; - updateSublayerList(); + if (!m_structuralLayer) { + m_structuralLayer.adoptNS([[CALayer alloc] init]); + structuralLayerChanged = true; + } } + + if (!structuralLayerChanged) + return; + + // Turn off default animations. + [m_structuralLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]]; + + updateLayerNames(); + // Update the properties of the structural layer. + updateLayerPosition(); + updateLayerSize(); + updateAnchorPoint(); + updateTransform(); + updateChildrenTransform(); + + // Set properties of m_layer to their default values, since these are expressed on on the structural layer. + CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); + [m_layer.get() setPosition:point]; + [m_layer.get() setAnchorPoint:CGPointMake(0.5f, 0.5f)]; + [m_layer.get() setTransform:CATransform3DIdentity]; + [m_layer.get() setOpacity:1]; + + // Move this layer to be a child of the transform layer. + [[m_layer.get() superlayer] replaceSublayer:m_layer.get() with:m_structuralLayer.get()]; + [m_structuralLayer.get() addSublayer:m_layer.get()]; + + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, m_layer.get(), m_structuralLayer.get()); + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, m_layer.get(), m_structuralLayer.get()); + + updateSublayerList(); updateOpacityOnLayer(); } +GraphicsLayerCA::StructuralLayerPurpose GraphicsLayerCA::structuralLayerPurpose() const +{ + if (preserves3D()) + return StructuralLayerForPreserves3D; + + if (isReplicated()) + return StructuralLayerForReplicaFlattening; + + return NoStructuralLayer; +} + void GraphicsLayerCA::updateLayerDrawsContent() { bool needTiledLayer = requiresTiledLayer(m_size); @@ -1087,6 +1348,12 @@ void GraphicsLayerCA::updateContentsImage() #endif [m_contentsLayer.get() setContents:(id)m_pendingContentsImage.get()]; m_pendingContentsImage = 0; + + if (m_contentsLayerClones) { + LayerMap::const_iterator end = m_contentsLayerClones->end(); + for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it) + [it->second.get() setContents:[m_contentsLayer.get() contents]]; + } updateContentsRect(); } else { @@ -1096,7 +1363,7 @@ void GraphicsLayerCA::updateContentsImage() } } -void GraphicsLayerCA::updateContentsVideo() +void GraphicsLayerCA::updateContentsMediaLayer() { // Video layer was set as m_contentsLayer, and will get parented in updateSublayerList(). if (m_contentsLayer) { @@ -1131,6 +1398,15 @@ void GraphicsLayerCA::updateContentsRect() [m_contentsLayer.get() setPosition:point]; [m_contentsLayer.get() setBounds:rect]; + + if (m_contentsLayerClones) { + LayerMap::const_iterator end = m_contentsLayerClones->end(); + for (LayerMap::const_iterator it = m_contentsLayerClones->begin(); it != end; ++it) { + CALayer *currLayer = it->second.get(); + [currLayer setPosition:point]; + [currLayer setBounds:rect]; + } + } } void GraphicsLayerCA::updateGeometryOrientation() @@ -1152,8 +1428,74 @@ void GraphicsLayerCA::updateGeometryOrientation() void GraphicsLayerCA::updateMaskLayer() { - CALayer* maskCALayer = m_maskLayer ? m_maskLayer->platformLayer() : 0; + CALayer *maskCALayer = m_maskLayer ? m_maskLayer->platformLayer() : 0; [m_layer.get() setMask:maskCALayer]; + + LayerMap* maskLayerCloneMap = m_maskLayer ? static_cast<GraphicsLayerCA*>(m_maskLayer)->primaryLayerClones() : 0; + + if (LayerMap* layerCloneMap = m_layerClones.get()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + CALayer *currLayer = it->second.get(); + + CALayer *maskClone = maskLayerCloneMap ? maskLayerCloneMap->get(it->first).get() : 0; + [currLayer setMask:maskClone]; + } + } +} + +void GraphicsLayerCA::updateReplicatedLayers() +{ + // Clone the descendants of the replicated layer, and parent under us. + ReplicaState replicaState(ReplicaState::ReplicaBranch); + + CALayer *replicaRoot = replicatedLayerRoot(replicaState); + if (!replicaRoot) + return; + + if (m_structuralLayer) + [m_structuralLayer.get() insertSublayer:replicaRoot atIndex:0]; + else + [m_layer.get() insertSublayer:replicaRoot atIndex:0]; +} + +// For now, this assumes that layers only ever have one replica, so replicaIndices contains only 0 and 1. +GraphicsLayerCA::CloneID GraphicsLayerCA::ReplicaState::cloneID() const +{ + size_t depth = m_replicaBranches.size(); + + const size_t bitsPerUChar = sizeof(UChar) * 8; + size_t vectorSize = (depth + bitsPerUChar - 1) / bitsPerUChar; + + Vector<UChar> result(vectorSize); + result.fill(0); + + // Create a string from the bit sequence which we can use to identify the clone. + // Note that the string may contain embedded nulls, but that's OK. + for (size_t i = 0; i < depth; ++i) { + UChar& currChar = result[i / bitsPerUChar]; + currChar = (currChar << 1) | m_replicaBranches[i]; + } + + return String::adopt(result); +} + +CALayer *GraphicsLayerCA::replicatedLayerRoot(ReplicaState& replicaState) +{ + // Limit replica nesting, to avoid 2^N explosion of replica layers. + if (!m_replicatedLayer || replicaState.replicaDepth() == ReplicaState::maxReplicaDepth) + return nil; + + GraphicsLayerCA* replicatedLayer = static_cast<GraphicsLayerCA*>(m_replicatedLayer); + + CALayer *clonedLayerRoot = replicatedLayer->fetchCloneLayers(this, replicaState, RootCloneLevel); + FloatPoint cloneRootPosition = replicatedLayer->positionForCloneRootLayer(); + + // Replica root has no offset or transform + [clonedLayerRoot setPosition:cloneRootPosition]; + [clonedLayerRoot setTransform:CATransform3DIdentity]; + + return clonedLayerRoot; } void GraphicsLayerCA::updateLayerAnimations() @@ -1163,10 +1505,8 @@ void GraphicsLayerCA::updateLayerAnimations() for (HashSet<AnimatedProperty>::const_iterator it = m_transitionPropertiesToRemove.begin(); it != end; ++it) { AnimatedPropertyID currProperty = static_cast<AnimatedPropertyID>(*it); // Remove all animations with this property in the key. - // We can't tell if this property is animating via a transition or animation here, but - // that's OK because the style system never sends both transitions and animations for the same property. for (int index = 0; ; ++index) { - if (!removeAnimationFromLayer(currProperty, index)) + if (!removeAnimationFromLayer(currProperty, "", index)) break; } } @@ -1182,21 +1522,21 @@ void GraphicsLayerCA::updateLayerAnimations() if (animationIt == m_runningKeyframeAnimations.end()) continue; - AnimationProcessingAction action = it->second; + const AnimationProcessingAction& processingInfo = it->second; const Vector<AnimationPair>& animations = animationIt->second; for (size_t i = 0; i < animations.size(); ++i) { const AnimationPair& currPair = animations[i]; - switch (action) { + switch (processingInfo.action) { case Remove: - removeAnimationFromLayer(static_cast<AnimatedPropertyID>(currPair.first), currPair.second); + removeAnimationFromLayer(static_cast<AnimatedPropertyID>(currPair.first), currKeyframeName, currPair.second); break; case Pause: - pauseAnimationOnLayer(static_cast<AnimatedPropertyID>(currPair.first), currPair.second); + pauseAnimationOnLayer(static_cast<AnimatedPropertyID>(currPair.first), currKeyframeName, currPair.second, processingInfo.timeOffset); break; } } - if (action == Remove) + if (processingInfo.action == Remove) m_runningKeyframeAnimations.remove(currKeyframeName); } @@ -1207,7 +1547,7 @@ void GraphicsLayerCA::updateLayerAnimations() if ((numAnimations = m_uncomittedAnimations.size())) { for (size_t i = 0; i < numAnimations; ++i) { const LayerAnimation& pendingAnimation = m_uncomittedAnimations[i]; - setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_index, pendingAnimation.m_beginTime); + setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_keyframesName, pendingAnimation.m_index, pendingAnimation.m_timeOffset); if (!pendingAnimation.m_keyframesName.isEmpty()) { // If this is a keyframe anim, we have to remember the association of keyframes name to property/index pairs, @@ -1229,19 +1569,28 @@ void GraphicsLayerCA::updateLayerAnimations() } } -void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedPropertyID property, int index, double beginTime) +void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedPropertyID property, const String& keyframesName, int index, double timeOffset) { PlatformLayer* layer = animatedLayer(property); - if (beginTime) { - NSTimeInterval time = [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil]; - [caAnim setBeginTime:time]; - } + [caAnim setTimeOffset:timeOffset]; - String animationName = animationIdentifier(property, index); + String animationName = animationIdentifier(property, keyframesName, index); [layer removeAnimationForKey:animationName]; [layer addAnimation:caAnim forKey:animationName]; + + if (LayerMap* layerCloneMap = animatedLayerClones(property)) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + // Skip immediate replicas, since they move with the original. + if (m_replicaLayer && isReplicatedRootClone(it->first)) + continue; + CALayer *currLayer = it->second.get(); + [currLayer removeAnimationForKey:animationName]; + [currLayer addAnimation:caAnim forKey:animationName]; + } + } } // Workaround for <rdar://problem/7311367> @@ -1259,18 +1608,29 @@ static void bug7311367Workaround(CALayer* transformLayer, const TransformationMa [transformLayer setTransform:caTransform]; } -bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, int index) +bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, const String& keyframesName, int index) { PlatformLayer* layer = animatedLayer(property); - String animationName = animationIdentifier(property, index); + String animationName = animationIdentifier(property, keyframesName, index); if (![layer animationForKey:animationName]) return false; [layer removeAnimationForKey:animationName]; - - bug7311367Workaround(m_transformLayer.get(), m_transform); + bug7311367Workaround(m_structuralLayer.get(), m_transform); + + if (LayerMap* layerCloneMap = animatedLayerClones(property)) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + // Skip immediate replicas, since they move with the original. + if (m_replicaLayer && isReplicatedRootClone(it->first)) + continue; + + CALayer *currLayer = it->second.get(); + [currLayer removeAnimationForKey:animationName]; + } + } return true; } @@ -1290,11 +1650,11 @@ static void copyAnimationProperties(CAPropertyAnimation* from, CAPropertyAnimati #endif } -void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, int index) +void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, const String& keyframesName, int index, double timeOffset) { PlatformLayer* layer = animatedLayer(property); - String animationName = animationIdentifier(property, index); + String animationName = animationIdentifier(property, keyframesName, index); CAAnimation* caAnim = [layer animationForKey:animationName]; if (!caAnim) @@ -1319,10 +1679,23 @@ void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, int ind pausedAnim = newAnim; } - double t = [layer convertTime:currentTimeToMediaTime(currentTime()) fromLayer:nil]; + // pausedAnim has the beginTime of caAnim already. [pausedAnim setSpeed:0]; - [pausedAnim setTimeOffset:t - [caAnim beginTime]]; + [pausedAnim setTimeOffset:timeOffset]; + [layer addAnimation:pausedAnim forKey:animationName]; // This will replace the running animation. + + // Pause the animations on the clones too. + if (LayerMap* layerCloneMap = animatedLayerClones(property)) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + // Skip immediate replicas, since they move with the original. + if (m_replicaLayer && isReplicatedRootClone(it->first)) + continue; + CALayer *currLayer = it->second.get(); + [currLayer addAnimation:pausedAnim forKey:animationName]; + } + } } #if ENABLE(3D_CANVAS) @@ -1337,7 +1710,7 @@ void GraphicsLayerCA::setContentsToGraphicsContext3D(const GraphicsContext3D* gr m_platformGraphicsContext3D = context; m_platformTexture = texture; - noteLayerPropertyChanged(ChildrenChanged); + noteSublayersChanged(); BEGIN_BLOCK_OBJC_EXCEPTIONS @@ -1346,9 +1719,11 @@ void GraphicsLayerCA::setContentsToGraphicsContext3D(const GraphicsContext3D* gr m_contentsLayer.adoptNS([[Canvas3DLayer alloc] initWithContext:static_cast<CGLContextObj>(m_platformGraphicsContext3D) texture:static_cast<GLuint>(m_platformTexture)]); #ifndef NDEBUG [m_contentsLayer.get() setName:@"3D Layer"]; -#endif +#endif + [m_contentsLayer.get() setLayerOwner:this]; } else { // remove the inner layer + [m_contentsLayer.get() setLayerOwner:0]; m_contentsLayer = 0; } @@ -1370,7 +1745,7 @@ void GraphicsLayerCA::repaintLayerDirtyRects() m_dirtyRects.clear(); } -bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double beginTime) +bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double timeOffset) { ASSERT(valueList.property() != AnimatedPropertyWebkitTransform); @@ -1396,14 +1771,14 @@ bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valu if (!valuesOK) return false; - m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, beginTime)); + m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, timeOffset)); END_BLOCK_OBJC_EXCEPTIONS; return true; } -bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double beginTime, const IntSize& boxSize) +bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double timeOffset, const IntSize& boxSize) { ASSERT(valueList.property() == AnimatedPropertyWebkitTransform); @@ -1450,7 +1825,7 @@ bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValue if (!validMatrices) break; - m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, beginTime)); + m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, timeOffset)); } END_BLOCK_OBJC_EXCEPTIONS; @@ -1663,25 +2038,42 @@ void GraphicsLayerCA::suspendAnimations(double time) double t = currentTimeToMediaTime(time ? time : currentTime()); [primaryLayer() setSpeed:0]; [primaryLayer() setTimeOffset:t]; + + // Suspend the animations on the clones too. + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + CALayer *currLayer = it->second.get(); + [currLayer setSpeed:0 ]; + [currLayer setTimeOffset:t]; + } + } } void GraphicsLayerCA::resumeAnimations() { [primaryLayer() setSpeed:1]; [primaryLayer() setTimeOffset:0]; + + // Resume the animations on the clones too. + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + CALayer *currLayer = it->second.get(); + [currLayer setSpeed:1]; + [currLayer setTimeOffset:0]; + } + } } -WebLayer* GraphicsLayerCA::hostLayerForSublayers() const +CALayer* GraphicsLayerCA::hostLayerForSublayers() const { - return m_transformLayer ? m_transformLayer.get() : m_layer.get(); + return m_structuralLayer.get() ? m_structuralLayer.get() : m_layer.get(); } -WebLayer* GraphicsLayerCA::layerForSuperlayer() const +CALayer* GraphicsLayerCA::layerForSuperlayer() const { - if (m_transformLayer) - return m_transformLayer.get(); - - return m_layer.get(); + return m_structuralLayer ? m_structuralLayer.get() : m_layer.get(); } CALayer* GraphicsLayerCA::animatedLayer(AnimatedPropertyID property) const @@ -1689,6 +2081,11 @@ CALayer* GraphicsLayerCA::animatedLayer(AnimatedPropertyID property) const return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer(); } +GraphicsLayerCA::LayerMap* GraphicsLayerCA::animatedLayerClones(AnimatedPropertyID property) const +{ + return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayerClones.get() : primaryLayerClones(); +} + PlatformLayer* GraphicsLayerCA::platformLayer() const { return primaryLayer(); @@ -1790,9 +2187,9 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer) #endif // move over animations - moveAnimation(AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get()); - moveAnimation(AnimatedPropertyOpacity, oldLayer.get(), m_layer.get()); - moveAnimation(AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get()); + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get()); + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyOpacity, oldLayer.get(), m_layer.get()); + moveOrCopyAnimationsForProperty(Move, AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get()); // need to tell new layer to draw itself setNeedsDisplay(); @@ -1847,9 +2244,232 @@ void GraphicsLayerCA::setupContentsLayer(CALayer* contentsLayer) } } +CALayer *GraphicsLayerCA::findOrMakeClone(CloneID cloneID, CALayer *sourceLayer, LayerMap* clones, CloneLevel cloneLevel) +{ + if (!sourceLayer) + return 0; + + CALayer *resultLayer; + + // Add with a dummy value to get an iterator for the insertion position, and a boolean that tells + // us whether there's an item there. This technique avoids two hash lookups. + RetainPtr<CALayer> dummy; + pair<LayerMap::iterator, bool> addResult = clones->add(cloneID, dummy); + if (!addResult.second) { + // Value was not added, so it exists already. + resultLayer = addResult.first->second.get(); + } else { + resultLayer = cloneLayer(sourceLayer, cloneLevel); +#ifndef NDEBUG + [resultLayer setName:[NSString stringWithFormat:@"Clone %d of layer %@", cloneID[0U], sourceLayer]]; +#endif + addResult.first->second = resultLayer; + } + + return resultLayer; +} + +void GraphicsLayerCA::ensureCloneLayers(CloneID cloneID, CALayer *& primaryLayer, CALayer *& structuralLayer, CALayer *& contentsLayer, CloneLevel cloneLevel) +{ + structuralLayer = nil; + contentsLayer = nil; + + if (!m_layerClones) + m_layerClones = new LayerMap; + + if (!m_structuralLayerClones && m_structuralLayer) + m_structuralLayerClones = new LayerMap; + + if (!m_contentsLayerClones && m_contentsLayer) + m_contentsLayerClones = new LayerMap; + + primaryLayer = findOrMakeClone(cloneID, m_layer.get(), m_layerClones.get(), cloneLevel); + structuralLayer = findOrMakeClone(cloneID, m_structuralLayer.get(), m_structuralLayerClones.get(), cloneLevel); + contentsLayer = findOrMakeClone(cloneID, m_contentsLayer.get(), m_contentsLayerClones.get(), cloneLevel); +} + +void GraphicsLayerCA::removeCloneLayers() +{ + m_layerClones = 0; + m_structuralLayerClones = 0; + m_contentsLayerClones = 0; +} + +FloatPoint GraphicsLayerCA::positionForCloneRootLayer() const +{ + // This can get called during a sync when we've just removed the m_replicaLayer. + if (!m_replicaLayer) + return FloatPoint(); + + FloatPoint replicaPosition = m_replicaLayer->replicatedLayerPosition(); + return FloatPoint(replicaPosition.x() + m_anchorPoint.x() * m_size.width(), + replicaPosition.y() + m_anchorPoint.y() * m_size.height()); +} + +void GraphicsLayerCA::propagateLayerChangeToReplicas() +{ + for (GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) { + GraphicsLayerCA* currLayerCA = static_cast<GraphicsLayerCA*>(currLayer); + if (!currLayerCA->hasCloneLayers()) + break; + + if (currLayerCA->replicaLayer()) + static_cast<GraphicsLayerCA*>(currLayerCA->replicaLayer())->noteLayerPropertyChanged(ReplicatedLayerChanged); + } +} + +CALayer *GraphicsLayerCA::fetchCloneLayers(GraphicsLayer* replicaRoot, ReplicaState& replicaState, CloneLevel cloneLevel) +{ + CALayer *primaryLayer; + CALayer *structuralLayer; + CALayer *contentsLayer; + ensureCloneLayers(replicaState.cloneID(), primaryLayer, structuralLayer, contentsLayer, cloneLevel); + + if (m_maskLayer) { + CALayer *maskClone = static_cast<GraphicsLayerCA*>(m_maskLayer)->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel); + [primaryLayer setMask:maskClone]; + } + + if (m_replicatedLayer) { + // We are a replica being asked for clones of our layers. + CALayer *replicaRoot = replicatedLayerRoot(replicaState); + if (!replicaRoot) + return nil; + + if (structuralLayer) { + [structuralLayer insertSublayer:replicaRoot atIndex:0]; + return structuralLayer; + } + + [primaryLayer insertSublayer:replicaRoot atIndex:0]; + return primaryLayer; + } + + const Vector<GraphicsLayer*>& childLayers = children(); + NSMutableArray* clonalSublayers = nil; + + CALayer *replicaLayer = nil; + if (m_replicaLayer && m_replicaLayer != replicaRoot) { + // We have nested replicas. Ask the replica layer for a clone of its contents. + replicaState.setBranchType(ReplicaState::ReplicaBranch); + replicaLayer = static_cast<GraphicsLayerCA*>(m_replicaLayer)->fetchCloneLayers(replicaRoot, replicaState, RootCloneLevel); + replicaState.setBranchType(ReplicaState::ChildBranch); + } + + if (replicaLayer || structuralLayer || contentsLayer || childLayers.size() > 0) { + clonalSublayers = [[NSMutableArray alloc] init]; + + if (structuralLayer) { + // Replicas render behind the actual layer content. + if (replicaLayer) + [clonalSublayers addObject:replicaLayer]; + + // Add the primary layer next. Even if we have negative z-order children, the primary layer always comes behind. + [clonalSublayers addObject:primaryLayer]; + } else if (contentsLayer) { + // FIXME: add the contents layer in the correct order with negative z-order children. + // This does not cause visible rendering issues because currently contents layers are only used + // for replaced elements that don't have children. + [clonalSublayers addObject:contentsLayer]; + } + + replicaState.push(ReplicaState::ChildBranch); + + size_t numChildren = childLayers.size(); + for (size_t i = 0; i < numChildren; ++i) { + GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]); + + CALayer *childLayer = curChild->fetchCloneLayers(replicaRoot, replicaState, IntermediateCloneLevel); + if (childLayer) + [clonalSublayers addObject:childLayer]; + } + + replicaState.pop(); + + [clonalSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]; + } + + CALayer *result; + if (structuralLayer) { + [structuralLayer setSublayers:clonalSublayers]; + + if (contentsLayer) { + // If we have a transform layer, then the contents layer is parented in the + // primary layer (which is itself a child of the transform layer). + [primaryLayer setSublayers:nil]; + [primaryLayer addSublayer:contentsLayer]; + } + + result = structuralLayer; + } else { + [primaryLayer setSublayers:clonalSublayers]; + result = primaryLayer; + } + + [clonalSublayers release]; + return result; +} + +CALayer *GraphicsLayerCA::cloneLayer(CALayer *layer, CloneLevel cloneLevel) +{ + static Class transformLayerClass = NSClassFromString(@"CATransformLayer"); + CALayer *newLayer = nil; + if ([layer isKindOfClass:transformLayerClass]) + newLayer = [transformLayerClass layer]; + else + newLayer = [CALayer layer]; + + [newLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]]; + + [newLayer setPosition:[layer position]]; + [newLayer setBounds:[layer bounds]]; + [newLayer setAnchorPoint:[layer anchorPoint]]; +#if HAVE_MODERN_QUARTZCORE + [newLayer setAnchorPointZ:[layer anchorPointZ]]; +#endif + [newLayer setTransform:[layer transform]]; + [newLayer setSublayerTransform:[layer sublayerTransform]]; + [newLayer setContents:[layer contents]]; + [newLayer setMasksToBounds:[layer masksToBounds]]; + [newLayer setDoubleSided:[layer isDoubleSided]]; + [newLayer setOpaque:[layer isOpaque]]; + [newLayer setBackgroundColor:[layer backgroundColor]]; + + if (cloneLevel == IntermediateCloneLevel) { + [newLayer setOpacity:[layer opacity]]; + moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyWebkitTransform, layer, newLayer); + moveOrCopyAnimationsForProperty(Copy, AnimatedPropertyOpacity, layer, newLayer); + } + + if (showDebugBorders()) { + setLayerBorderColor(newLayer, Color(255, 122, 251)); + [newLayer setBorderWidth:2]; + } + + return newLayer; +} + void GraphicsLayerCA::setOpacityInternal(float accumulatedOpacity) { - [(preserves3D() ? m_layer.get() : primaryLayer()) setOpacity:accumulatedOpacity]; + LayerMap* layerCloneMap = 0; + + if (preserves3D()) { + [m_layer.get() setOpacity:accumulatedOpacity]; + layerCloneMap = m_layerClones.get(); + } else { + [primaryLayer() setOpacity:accumulatedOpacity]; + layerCloneMap = primaryLayerClones(); + } + + if (layerCloneMap) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + if (m_replicaLayer && isReplicatedRootClone(it->first)) + continue; + CALayer *currLayer = it->second.get(); + [currLayer setOpacity:m_opacity]; + } + } } void GraphicsLayerCA::updateOpacityOnLayer() @@ -1860,9 +2480,27 @@ void GraphicsLayerCA::updateOpacityOnLayer() distributeOpacity(parent() ? parent()->accumulatedOpacity() : 1); #else [primaryLayer() setOpacity:m_opacity]; + + if (LayerMap* layerCloneMap = primaryLayerClones()) { + LayerMap::const_iterator end = layerCloneMap->end(); + for (LayerMap::const_iterator it = layerCloneMap->begin(); it != end; ++it) { + if (m_replicaLayer && isReplicatedRootClone(it->first)) + continue; + + CALayer *currLayer = it->second.get(); + [currLayer setOpacity:m_opacity]; + } + + } #endif } +void GraphicsLayerCA::noteSublayersChanged() +{ + noteLayerPropertyChanged(ChildrenChanged); + propagateLayerChangeToReplicas(); +} + void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags) { if (!m_uncommittedChanges && m_client) diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h index 7aaf95d..e9f64be 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -104,22 +104,19 @@ private: bool hasClosedCaptions() const; void setClosedCaptionsVisible(bool); - void setEndTime(float time); - - int dataRate() const; - MediaPlayer::NetworkState networkState() const { return m_networkState; } MediaPlayer::ReadyState readyState() const { return m_readyState; } PassRefPtr<TimeRanges> buffered() const; float maxTimeSeekable() const; unsigned bytesLoaded() const; - bool totalBytesKnown() const; unsigned totalBytes() const; void setVisible(bool); void setSize(const IntSize&); + virtual bool hasAvailableVideoFrame() const; + void paint(GraphicsContext*, const IntRect&); void paintCurrentFrameInContext(GraphicsContext*, const IntRect&); @@ -176,18 +173,19 @@ private: Timer<MediaPlayerPrivate> m_seekTimer; MediaPlayer::NetworkState m_networkState; MediaPlayer::ReadyState m_readyState; - bool m_startedPlaying; - bool m_isStreaming; - bool m_visible; IntRect m_rect; FloatSize m_scaleFactor; unsigned m_enabledTrackCount; unsigned m_totalTrackCount; - bool m_hasUnsupportedTracks; float m_reportedDuration; float m_cachedDuration; float m_timeToRestore; RetainPtr<QTMovieLayer> m_qtVideoLayer; + bool m_startedPlaying; + bool m_isStreaming; + bool m_visible; + bool m_hasUnsupportedTracks; + bool m_videoFrameHasDrawn; #if DRAW_FRAME_RATE int m_frameCountWhilePlaying; double m_timeStartedPlaying; diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index dfb5958..dd87bb5 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -204,17 +204,18 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) - , m_startedPlaying(false) - , m_isStreaming(false) - , m_visible(false) , m_rect() , m_scaleFactor(1, 1) , m_enabledTrackCount(0) , m_totalTrackCount(0) + , m_reportedDuration(-1) + , m_cachedDuration(-1) + , m_timeToRestore(-1) + , m_startedPlaying(false) + , m_isStreaming(false) + , m_visible(false) , m_hasUnsupportedTracks(false) - , m_reportedDuration(-1.0f) - , m_cachedDuration(-1.0f) - , m_timeToRestore(-1.0f) + , m_videoFrameHasDrawn(false) #if DRAW_FRAME_RATE , m_frameCountWhilePlaying(0) , m_timeStartedPlaying(0) @@ -449,7 +450,7 @@ void MediaPlayerPrivate::createQTMovieLayer() // later via acceleratedRenderingStateChanged(). GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player); if (videoGraphicsLayer) - videoGraphicsLayer->setContentsToVideo((PlatformLayer *)m_qtVideoLayer.get()); + videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer.get()); } #endif } @@ -498,6 +499,9 @@ MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::preferredRenderingMod void MediaPlayerPrivate::setUpVideoRendering() { + if (!isReadyForRendering()) + return; + MediaRenderingMode currentMode = currentRenderingMode(); MediaRenderingMode preferredMode = preferredRenderingMode(); if (currentMode == preferredMode && currentMode != MediaRenderingNone) @@ -556,6 +560,7 @@ void MediaPlayerPrivate::load(const String& url) m_player->readyStateChanged(); } cancelSeek(); + m_videoFrameHasDrawn = false; [m_objcObserver.get() setDelayCallbacks:YES]; @@ -651,7 +656,7 @@ void MediaPlayerPrivate::doSeek() [m_qtMovie.get() setRate:0]; [m_qtMovie.get() setCurrentTime:qttime]; - // restore playback only if not at end, othewise QTMovie will loop + // restore playback only if not at end, otherwise QTMovie will loop float timeAfterSeek = currentTime(); if (oldRate && timeAfterSeek < duration()) [m_qtMovie.get() setRate:oldRate]; @@ -687,10 +692,6 @@ void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*) } } -void MediaPlayerPrivate::setEndTime(float) -{ -} - bool MediaPlayerPrivate::paused() const { if (!metaDataAvailable()) @@ -765,7 +766,7 @@ void MediaPlayerPrivate::setClosedCaptionsVisible(bool closedCaptionsVisible) #if USE(ACCELERATED_COMPOSITING) && (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) if (closedCaptionsVisible && m_qtVideoLayer) { - // Captions will be rendered upsided down unless we flag the movie as flipped (again). See <rdar://7408440>. + // Captions will be rendered upside down unless we flag the movie as flipped (again). See <rdar://7408440>. [m_qtVideoLayer.get() setGeometryFlipped:YES]; } #endif @@ -796,13 +797,6 @@ void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch) createQTMovie([movieAttributes valueForKey:QTMovieURLAttribute], movieAttributes); } -int MediaPlayerPrivate::dataRate() const -{ - if (!metaDataAvailable()) - return 0; - return wkQTMovieDataRate(m_qtMovie.get()); -} - PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const { RefPtr<TimeRanges> timeRanges = TimeRanges::create(); @@ -839,11 +833,6 @@ unsigned MediaPlayerPrivate::bytesLoaded() const return totalBytes() * maxTimeLoaded() / dur; } -bool MediaPlayerPrivate::totalBytesKnown() const -{ - return totalBytes() > 0; -} - unsigned MediaPlayerPrivate::totalBytes() const { if (!metaDataAvailable()) @@ -981,7 +970,7 @@ void MediaPlayerPrivate::updateStates() } } - if (isReadyForRendering() && !hasSetUpVideoRendering()) + if (!hasSetUpVideoRendering()) setUpVideoRendering(); if (seeking()) @@ -1056,8 +1045,11 @@ void MediaPlayerPrivate::didEnd() // Hang onto the current time and use it as duration from now on since QuickTime is telling us we // are at the end. Do this because QuickTime sometimes reports one time for duration and stops - // playback at another time, which causes problems in HTMLMediaElement. - m_cachedDuration = currentTime(); + // playback at another time, which causes problems in HTMLMediaElement. QTKit's 'ended' event + // fires when playing in reverse so don't update duration when at time zero! + float now = currentTime(); + if (now > 0) + m_cachedDuration = now; updateStates(); m_player->timeChanged(); @@ -1078,14 +1070,27 @@ void MediaPlayerPrivate::setVisible(bool b) { if (m_visible != b) { m_visible = b; - if (b) { - if (m_readyState >= MediaPlayer::HaveMetadata) - setUpVideoRendering(); - } else + if (b) + setUpVideoRendering(); + else tearDownVideoRendering(); } } +bool MediaPlayerPrivate::hasAvailableVideoFrame() const +{ + // When using a QTMovieLayer return true as soon as the movie reaches QTMovieLoadStatePlayable + // because although we don't *know* when the first frame has decoded, by the time we get and + // process the notification a frame should have propagated the VisualContext and been set on + // the layer. + if (currentRenderingMode() == MediaRenderingMovieLayer) + return m_readyState >= MediaPlayer::HaveCurrentData; + + // When using the software renderer QuickTime signals that a frame is available so we might as well + // wait until we know that a frame has been drawn. + return m_videoFrameHasDrawn; +} + void MediaPlayerPrivate::repaint() { if (m_hasUnsupportedTracks) @@ -1100,6 +1105,7 @@ void MediaPlayerPrivate::repaint() m_timeStartedPlaying = [NSDate timeIntervalSinceReferenceDate]; } #endif + m_videoFrameHasDrawn = true; m_player->repaint(); } @@ -1404,7 +1410,7 @@ void MediaPlayerPrivate::acceleratedRenderingStateChanged() if (currentRenderingMode() == MediaRenderingMovieLayer) { GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player); if (videoGraphicsLayer) - videoGraphicsLayer->setContentsToVideo((PlatformLayer *)m_qtVideoLayer.get()); + videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer.get()); } } #endif diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index 97a7251..ef7c58f 100644 --- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -55,8 +55,7 @@ using namespace std; namespace WebCore { const float smallCapsFontSizeMultiplier = 0.7f; -const float contextDPI = 72.0f; -static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return x * (contextDPI / (contextDPI * unitsPerEm)); } +static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return x / unitsPerEm; } static bool initFontData(SimpleFontData* fontData) { @@ -149,7 +148,6 @@ void SimpleFontData::platformInit() m_styleGroup = 0; #endif #if USE(ATSUI) - m_ATSUStyleInitialized = false; m_ATSUMirrors = false; m_checkedShapesArabic = false; m_shapesArabic = false; @@ -318,8 +316,9 @@ void SimpleFontData::platformDestroy() wkReleaseStyleGroup(m_styleGroup); #endif #if USE(ATSUI) - if (m_ATSUStyleInitialized) - ATSUDisposeStyle(m_ATSUStyle); + HashMap<unsigned, ATSUStyle>::iterator end = m_ATSUStyleMap.end(); + for (HashMap<unsigned, ATSUStyle>::iterator it = m_ATSUStyleMap.begin(); it != end; ++it) + ATSUDisposeStyle(it->second); #endif } @@ -445,13 +444,15 @@ CTFontRef SimpleFontData::getCTFont() const return m_CTFont.get(); } -CFDictionaryRef SimpleFontData::getCFStringAttributes(TextRenderingMode textMode) const +CFDictionaryRef SimpleFontData::getCFStringAttributes(TypesettingFeatures typesettingFeatures) const { - if (m_CFStringAttributes) - return m_CFStringAttributes.get(); + unsigned key = typesettingFeatures + 1; + pair<HashMap<unsigned, RetainPtr<CFDictionaryRef> >::iterator, bool> addResult = m_CFStringAttributes.add(key, RetainPtr<CFDictionaryRef>()); + RetainPtr<CFDictionaryRef>& attributesDictionary = addResult.first->second; + if (!addResult.second) + return attributesDictionary.get(); - bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision; - bool allowLigatures = platformData().allowsLigatures() || allowKerning; + bool allowLigatures = platformData().allowsLigatures() || (typesettingFeatures & Ligatures); static const int ligaturesNotAllowedValue = 0; static CFNumberRef ligaturesNotAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesNotAllowedValue); @@ -459,25 +460,25 @@ CFDictionaryRef SimpleFontData::getCFStringAttributes(TextRenderingMode textMode static const int ligaturesAllowedValue = 1; static CFNumberRef ligaturesAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesAllowedValue); - if (!allowKerning) { + if (!(typesettingFeatures & Kerning)) { static const float kerningAdjustmentValue = 0; static CFNumberRef kerningAdjustment = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &kerningAdjustmentValue); static const void* keysWithKerningDisabled[] = { kCTFontAttributeName, kCTKernAttributeName, kCTLigatureAttributeName }; const void* valuesWithKerningDisabled[] = { getCTFont(), kerningAdjustment, allowLigatures ? ligaturesAllowed : ligaturesNotAllowed }; - m_CFStringAttributes.adoptCF(CFDictionaryCreate(NULL, keysWithKerningDisabled, valuesWithKerningDisabled, + attributesDictionary.adoptCF(CFDictionaryCreate(NULL, keysWithKerningDisabled, valuesWithKerningDisabled, sizeof(keysWithKerningDisabled) / sizeof(*keysWithKerningDisabled), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); } else { // By omitting the kCTKernAttributeName attribute, we get Core Text's standard kerning. static const void* keysWithKerningEnabled[] = { kCTFontAttributeName, kCTLigatureAttributeName }; const void* valuesWithKerningEnabled[] = { getCTFont(), allowLigatures ? ligaturesAllowed : ligaturesNotAllowed }; - m_CFStringAttributes.adoptCF(CFDictionaryCreate(NULL, keysWithKerningEnabled, valuesWithKerningEnabled, + attributesDictionary.adoptCF(CFDictionaryCreate(NULL, keysWithKerningEnabled, valuesWithKerningEnabled, sizeof(keysWithKerningEnabled) / sizeof(*keysWithKerningEnabled), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); } - return m_CFStringAttributes.get(); + return attributesDictionary.get(); } #endif diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm index 56b28e6..641d421 100644 --- a/WebCore/platform/graphics/mac/WebLayer.mm +++ b/WebCore/platform/graphics/mac/WebLayer.mm @@ -153,6 +153,13 @@ using namespace WebCore; } } +- (void)display +{ + [super display]; + if (m_layerOwner) + m_layerOwner->didDisplay(self); +} + - (void)drawInContext:(CGContextRef)context { [WebLayer drawContents:m_layerOwner ofLayer:self intoContext:context]; diff --git a/WebCore/platform/graphics/mac/WebTiledLayer.mm b/WebCore/platform/graphics/mac/WebTiledLayer.mm index a1f5693..97ba233 100644 --- a/WebCore/platform/graphics/mac/WebTiledLayer.mm +++ b/WebCore/platform/graphics/mac/WebTiledLayer.mm @@ -92,6 +92,13 @@ using namespace WebCore; } } +- (void)display +{ + [super display]; + if (m_layerOwner) + m_layerOwner->didDisplay(self); +} + - (void)drawInContext:(CGContextRef)ctx { [WebLayer drawContents:m_layerOwner ofLayer:self intoContext:ctx]; |