summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/mac
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics/mac')
-rw-r--r--WebCore/platform/graphics/mac/Canvas3DLayer.mm10
-rw-r--r--WebCore/platform/graphics/mac/ComplexTextController.cpp65
-rw-r--r--WebCore/platform/graphics/mac/ComplexTextController.h31
-rw-r--r--WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp67
-rw-r--r--WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp59
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp181
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContextMac.mm52
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.h161
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.mm956
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h18
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm74
-rw-r--r--WebCore/platform/graphics/mac/SimpleFontDataMac.mm29
-rw-r--r--WebCore/platform/graphics/mac/WebLayer.mm7
-rw-r--r--WebCore/platform/graphics/mac/WebTiledLayer.mm7
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];