diff options
author | Feng Qian <fqian@google.com> | 2009-06-17 12:12:20 -0700 |
---|---|---|
committer | Feng Qian <fqian@google.com> | 2009-06-17 12:12:20 -0700 |
commit | 5f1ab04193ad0130ca8204aadaceae083aca9881 (patch) | |
tree | 5a92cd389e2cfe7fb67197ce14b38469462379f8 /WebCore/platform/graphics/mac | |
parent | 194315e5a908cc8ed67d597010544803eef1ac59 (diff) | |
download | external_webkit-5f1ab04193ad0130ca8204aadaceae083aca9881.zip external_webkit-5f1ab04193ad0130ca8204aadaceae083aca9881.tar.gz external_webkit-5f1ab04193ad0130ca8204aadaceae083aca9881.tar.bz2 |
Get WebKit r44544.
Diffstat (limited to 'WebCore/platform/graphics/mac')
-rw-r--r-- | WebCore/platform/graphics/mac/ColorMac.h | 2 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/ColorMac.mm | 48 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/CoreTextController.cpp | 32 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/CoreTextController.h | 4 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/FontCacheMac.mm | 16 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/FontMac.mm | 16 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/FontMacATSUI.mm | 49 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/FontMacCoreText.cpp | 4 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/FontPlatformData.h | 2 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/GraphicsContextMac.mm | 11 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/GraphicsLayerCA.h | 3 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/GraphicsLayerCA.mm | 98 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h | 6 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm | 294 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/SimpleFontDataMac.mm | 105 | ||||
-rw-r--r-- | WebCore/platform/graphics/mac/WebLayer.mm | 1 |
16 files changed, 459 insertions, 232 deletions
diff --git a/WebCore/platform/graphics/mac/ColorMac.h b/WebCore/platform/graphics/mac/ColorMac.h index 830e9d9..8a5ce31 100644 --- a/WebCore/platform/graphics/mac/ColorMac.h +++ b/WebCore/platform/graphics/mac/ColorMac.h @@ -41,7 +41,7 @@ namespace WebCore { // These functions assume NSColors are in DeviceRGB colorspace Color colorFromNSColor(NSColor *); - NSColor* nsColor(const Color&); + NSColor *nsColor(const Color&); bool usesTestModeFocusRingColor(); void setUsesTestModeFocusRingColor(bool); diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm index 1c4350c..05dd78d 100644 --- a/WebCore/platform/graphics/mac/ColorMac.mm +++ b/WebCore/platform/graphics/mac/ColorMac.mm @@ -24,13 +24,10 @@ */ #import "config.h" -#import "Color.h" #import "ColorMac.h" -#import <AppKit/AppKit.h> -#import <wtf/Assertions.h> -#import <wtf/StdLibExtras.h> #import <wtf/RetainPtr.h> +#import <wtf/StdLibExtras.h> @interface WebCoreControlTintObserver : NSObject + (void)controlTintDidChange; @@ -47,7 +44,13 @@ static bool useOldAquaFocusRingColor; static RGBA32 makeRGBAFromNSColor(NSColor *c) { - return makeRGBA((int)(255 * [c redComponent]), (int)(255 * [c greenComponent]), (int)(255 * [c blueComponent]), (int)(255 * [c alphaComponent])); + CGFloat redComponent; + CGFloat greenComponent; + CGFloat blueComponent; + CGFloat alpha; + [c getRed:&redComponent green:&greenComponent blue:&blueComponent alpha:&alpha]; + + return makeRGBA(255 * redComponent, 255 * greenComponent, 255 * blueComponent, 255 * alpha); } Color colorFromNSColor(NSColor *c) @@ -55,21 +58,21 @@ Color colorFromNSColor(NSColor *c) return Color(makeRGBAFromNSColor(c)); } -NSColor* nsColor(const Color& color) +NSColor *nsColor(const Color& color) { - unsigned c = color.rgb(); + RGBA32 c = color.rgb(); switch (c) { case 0: { // Need this to avoid returning nil because cachedRGBAValues will default to 0. - DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, clearColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:0.0f])); + DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, clearColor, ([NSColor colorWithDeviceRed:0 green:0 blue:0 alpha:0])); return clearColor.get(); } case Color::black: { - DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, blackColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:1.0f])); + DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, blackColor, ([NSColor colorWithDeviceRed:0 green:0 blue:0 alpha:1])); return blackColor.get(); } case Color::white: { - DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, whiteColor, ([NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:1.0f])); + DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, whiteColor, ([NSColor colorWithDeviceRed:1 green:1 blue:1 alpha:1])); return whiteColor.get(); } default: { @@ -81,10 +84,10 @@ NSColor* nsColor(const Color& color) if (cachedRGBAValues[i] == c) return cachedColors[i].get(); - NSColor* result = [NSColor colorWithDeviceRed:color.red() / 255.0f - green:color.green() / 255.0f - blue:color.blue() / 255.0f - alpha:color.alpha() /255.0f]; + NSColor *result = [NSColor colorWithDeviceRed:static_cast<CGFloat>(color.red()) / 255 + green:static_cast<CGFloat>(color.green()) / 255 + blue:static_cast<CGFloat>(color.blue()) / 255 + alpha:static_cast<CGFloat>(color.alpha()) /255]; static int cursor; cachedRGBAValues[cursor] = c; @@ -96,16 +99,13 @@ NSColor* nsColor(const Color& color) } } -static CGColorRef CGColorFromNSColor(NSColor* color) +static CGColorRef CGColorFromNSColor(NSColor *color) { // This needs to always use device colorspace so it can de-calibrate the color for // CGColor to possibly recalibrate it. - NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; - CGFloat red = [deviceColor redComponent]; - CGFloat green = [deviceColor greenComponent]; - CGFloat blue = [deviceColor blueComponent]; - CGFloat alpha = [deviceColor alphaComponent]; - const CGFloat components[4] = { red, green, blue, alpha }; + CGFloat components[4]; + NSColor *deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + [deviceColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]]; static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB(); CGColorRef cgColor = CGColorCreate(deviceRGBColorSpace, components); return cgColor; @@ -130,10 +130,10 @@ Color focusRingColor() [WebCoreControlTintObserver controlTintDidChange]; tintIsKnown = true; } - + if (usesTestModeFocusRingColor()) return oldAquaFocusRingColor; - + return systemFocusRingColor; } @@ -153,7 +153,7 @@ void setUsesTestModeFocusRingColor(bool newValue) + (void)controlTintDidChange { - NSColor* color = [[NSColor keyboardFocusIndicatorColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + NSColor *color = [[NSColor keyboardFocusIndicatorColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; WebCore::systemFocusRingColor = WebCore::makeRGBAFromNSColor(color); } diff --git a/WebCore/platform/graphics/mac/CoreTextController.cpp b/WebCore/platform/graphics/mac/CoreTextController.cpp index 49e83c4..05f29b5 100644 --- a/WebCore/platform/graphics/mac/CoreTextController.cpp +++ b/WebCore/platform/graphics/mac/CoreTextController.cpp @@ -100,7 +100,7 @@ CoreTextController::CoreTextRun::CoreTextRun(const SimpleFontData* fontData, con m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get())); } -CoreTextController::CoreTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection) +CoreTextController::CoreTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts) : m_font(*font) , m_run(run) , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection) @@ -112,6 +112,7 @@ CoreTextController::CoreTextController(const Font* font, const TextRun& run, boo , m_currentRun(0) , m_glyphInCurrentRun(0) , m_finalRoundingWidth(0) + , m_fallbackFonts(fallbackFonts) , m_lastRoundingGlyph(0) { m_padding = m_run.padding(); @@ -156,12 +157,12 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) if (x <= adjustedAdvance) { CFIndex hitIndex = coreTextRun.indexAt(j); int stringLength = coreTextRun.stringLength(); - TextBreakIterator* characterIterator = characterBreakIterator(coreTextRun.characters(), stringLength); + TextBreakIterator* cursorPositionIterator = cursorMovementIterator(coreTextRun.characters(), stringLength); int clusterStart; - if (isTextBreak(characterIterator, hitIndex)) + if (isTextBreak(cursorPositionIterator, hitIndex)) clusterStart = hitIndex; else { - clusterStart = textBreakPreceding(characterIterator, hitIndex); + clusterStart = textBreakPreceding(cursorPositionIterator, hitIndex); if (clusterStart == TextBreakDone) clusterStart = 0; } @@ -169,7 +170,7 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) if (!includePartialGlyphs) return coreTextRun.stringLocation() + clusterStart; - int clusterEnd = textBreakFollowing(characterIterator, hitIndex); + int clusterEnd = textBreakFollowing(cursorPositionIterator, hitIndex); if (clusterEnd == TextBreakDone) clusterEnd = stringLength; @@ -179,7 +180,7 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) // reordering and on font fallback should occur within a CTLine. if (clusterEnd - clusterStart > 1) { int firstGlyphBeforeCluster = j - 1; - while (firstGlyphBeforeCluster && coreTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) { + while (firstGlyphBeforeCluster >= 0 && coreTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) { CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width; clusterWidth += width; x += width; @@ -359,6 +360,9 @@ void CoreTextController::collectCoreTextRunsForCharacters(const UChar* cp, unsig return; } + if (m_fallbackFonts && fontData != m_font.primaryFont()) + m_fallbackFonts->add(fontData); + RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull)); RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes())); @@ -426,7 +430,7 @@ void CoreTextController::adjustGlyphsAndAdvances() bool lastRun = r + 1 == runCount; const UChar* cp = coreTextRun.characters(); - CGFloat roundedSpaceWidth = roundCGFloat(fontData->m_spaceWidth); + CGFloat roundedSpaceWidth = roundCGFloat(fontData->spaceWidth()); bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances(); bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_padding) && !m_run.spacingDisabled(); @@ -444,29 +448,29 @@ void CoreTextController::adjustGlyphsAndAdvances() nextCh = *(m_coreTextRuns[r + 1].characters() + m_coreTextRuns[r + 1].indexAt(0)); bool treatAsSpace = Font::treatAsSpace(ch); - CGGlyph glyph = treatAsSpace ? fontData->m_spaceGlyph : glyphs[i]; - CGSize advance = treatAsSpace ? CGSizeMake(fontData->m_spaceWidth, advances[i].height) : advances[i]; + CGGlyph glyph = treatAsSpace ? fontData->spaceGlyph() : glyphs[i]; + CGSize advance = treatAsSpace ? CGSizeMake(fontData->spaceWidth(), advances[i].height) : advances[i]; if (ch == '\t' && m_run.allowTabs()) { float tabWidth = m_font.tabWidth(); advance.width = tabWidth - fmodf(m_run.xPos() + m_totalWidth, tabWidth); } else if (ch == zeroWidthSpace || Font::treatAsZeroWidthSpace(ch) && !treatAsSpace) { advance.width = 0; - glyph = fontData->m_spaceGlyph; + glyph = fontData->spaceGlyph(); } float roundedAdvanceWidth = roundf(advance.width); if (roundsAdvances) advance.width = roundedAdvanceWidth; - advance.width += fontData->m_syntheticBoldOffset; + advance.width += fontData->syntheticBoldOffset(); // We special case spaces in two ways when applying word rounding. // First, we round spaces to an adjusted width in all fonts. // Second, in fixed-pitch fonts we ensure that all glyphs that // match the width of the space glyph have the same width as the space glyph. - if (roundedAdvanceWidth == roundedSpaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding()) - advance.width = fontData->m_adjustedSpaceWidth; + if (roundedAdvanceWidth == roundedSpaceWidth && (fontData->pitch() == FixedPitch || glyph == fontData->spaceGlyph()) && m_run.applyWordRounding()) + advance.width = fontData->adjustedSpaceWidth(); if (hasExtraSpacing) { // If we're a glyph with an advance, go ahead and add in letter-spacing. @@ -475,7 +479,7 @@ void CoreTextController::adjustGlyphsAndAdvances() advance.width += m_font.letterSpacing(); // Handle justification and word-spacing. - if (glyph == fontData->m_spaceGlyph) { + if (glyph == fontData->spaceGlyph()) { // Account for padding. WebCore uses space padding to justify text. // We distribute the specified padding over the available spaces in the run. if (m_padding) { diff --git a/WebCore/platform/graphics/mac/CoreTextController.h b/WebCore/platform/graphics/mac/CoreTextController.h index 8dbb7fb..4dd6f93 100644 --- a/WebCore/platform/graphics/mac/CoreTextController.h +++ b/WebCore/platform/graphics/mac/CoreTextController.h @@ -37,7 +37,7 @@ namespace WebCore { class CoreTextController { public: - CoreTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false); + CoreTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0); // Advance and emit glyphs up to the specified character. void advance(unsigned to, GlyphBuffer* = 0); @@ -106,6 +106,8 @@ private: float m_padding; float m_padPerSpace; + HashSet<const SimpleFontData*>* m_fallbackFonts; + unsigned m_lastRoundingGlyph; }; diff --git a/WebCore/platform/graphics/mac/FontCacheMac.mm b/WebCore/platform/graphics/mac/FontCacheMac.mm index 2202459..2730d5a 100644 --- a/WebCore/platform/graphics/mac/FontCacheMac.mm +++ b/WebCore/platform/graphics/mac/FontCacheMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com> * * Redistribution and use in source and binary forms, with or without @@ -44,16 +44,30 @@ typedef int NSInteger; namespace WebCore { +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCenterRef, void* observer, CFStringRef name, const void *, CFDictionaryRef) +{ + ASSERT_UNUSED(observer, observer == fontCache()); + ASSERT_UNUSED(name, CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification)); + fontCache()->invalidate(); +} +#else static void fontCacheATSNotificationCallback(ATSFontNotificationInfoRef, void*) { fontCache()->invalidate(); } +#endif void FontCache::platformInit() { wkSetUpFontCache(); +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this, fontCacheRegisteredFontsChangedNotificationCallback, kCTFontManagerRegisteredFontsChangedNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately); +#else + // kCTFontManagerRegisteredFontsChangedNotification does not exist on Leopard and earlier. // FIXME: Passing kATSFontNotifyOptionReceiveWhileSuspended may be an overkill and does not seem to work anyway. ATSFontNotificationSubscribe(fontCacheATSNotificationCallback, kATSFontNotifyOptionReceiveWhileSuspended, 0, 0); +#endif } static int toAppKitFontWeight(FontWeight fontWeight) diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm index dc86c4b..df9494a 100644 --- a/WebCore/platform/graphics/mac/FontMac.mm +++ b/WebCore/platform/graphics/mac/FontMac.mm @@ -28,7 +28,6 @@ #import "Logging.h" #import "SimpleFontData.h" #import "WebCoreSystemInterface.h" -#import "WebCoreTextRenderer.h" #import <AppKit/AppKit.h> #define SYNTHETIC_OBLIQUE_ANGLE 14 @@ -43,12 +42,17 @@ using namespace std; namespace WebCore { +bool Font::canReturnFallbackFontsForComplexText() +{ + return true; +} + void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { CGContextRef cgContext = context->platformContext(); bool originalShouldUseFontSmoothing = wkCGContextGetShouldSmoothFonts(cgContext); - bool newShouldUseFontSmoothing = WebCoreShouldUseFontSmoothing(); + bool newShouldUseFontSmoothing = shouldUseSmoothing(); if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing) CGContextSetShouldSmoothFonts(cgContext, newShouldUseFontSmoothing); @@ -99,8 +103,8 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons context->setFillColor(shadowFillColor); CGContextSetTextPosition(cgContext, point.x() + shadowSize.width(), point.y() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); - if (font->m_syntheticBoldOffset) { - CGContextSetTextPosition(cgContext, point.x() + shadowSize.width() + font->m_syntheticBoldOffset, point.y() + shadowSize.height()); + if (font->syntheticBoldOffset()) { + CGContextSetTextPosition(cgContext, point.x() + shadowSize.width() + font->syntheticBoldOffset(), point.y() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } context->setFillColor(fillColor); @@ -108,8 +112,8 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons CGContextSetTextPosition(cgContext, point.x(), point.y()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); - if (font->m_syntheticBoldOffset) { - CGContextSetTextPosition(cgContext, point.x() + font->m_syntheticBoldOffset, point.y()); + if (font->syntheticBoldOffset()) { + CGContextSetTextPosition(cgContext, point.x() + font->syntheticBoldOffset(), point.y()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm index 3794149..051abb7 100644 --- a/WebCore/platform/graphics/mac/FontMacATSUI.mm +++ b/WebCore/platform/graphics/mac/FontMacATSUI.mm @@ -47,13 +47,15 @@ namespace WebCore { struct ATSULayoutParameters : Noncopyable { - ATSULayoutParameters(const TextRun& run) + ATSULayoutParameters(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts = 0) : m_run(run) , m_font(0) , m_hasSyntheticBold(false) , m_syntheticBoldPass(false) , m_padPerSpace(0) - {} + , m_fallbackFonts(fallbackFonts) + { + } ~ATSULayoutParameters() { @@ -73,6 +75,7 @@ struct ATSULayoutParameters : Noncopyable bool m_hasSyntheticBold; bool m_syntheticBoldPass; float m_padPerSpace; + HashSet<const SimpleFontData*>* m_fallbackFonts; }; static TextRun copyRunForDirectionalOverrideIfNecessary(const TextRun& run, OwnArrayPtr<UChar>& charactersWithOverride) @@ -124,7 +127,7 @@ static void initializeATSUStyle(const SimpleFontData* fontData) ATSUFontID fontID = fontData->platformData().m_atsuFontID; if (!fontID) { - LOG_ERROR("unable to get ATSUFontID for %@", fontData->m_font.font()); + LOG_ERROR("unable to get ATSUFontID for %@", fontData->platformData().font()); return; } @@ -134,7 +137,7 @@ static void initializeATSUStyle(const SimpleFontData* fontData) LOG_ERROR("ATSUCreateStyle failed (%d)", status); CGAffineTransform transform = CGAffineTransformMakeScale(1, -1); - if (fontData->m_font.m_syntheticOblique) + if (fontData->platformData().m_syntheticOblique) transform = CGAffineTransformConcat(transform, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0)); Fixed fontSize = FloatToFixed(fontData->platformData().m_size); ByteCount styleSizes[4] = { sizeof(Fixed), sizeof(ATSUFontID), sizeof(CGAffineTransform), sizeof(Fract) }; @@ -180,7 +183,6 @@ static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef bool shouldRound = false; bool syntheticBoldPass = params->m_syntheticBoldPass; Fixed syntheticBoldOffset = 0; - ATSGlyphRef spaceGlyph = 0; bool hasExtraSpacing = (params->m_font->letterSpacing() || params->m_font->wordSpacing() || params->m_run.padding()) && !params->m_run.spacingDisabled(); float padding = params->m_run.padding(); // In the CoreGraphics code path, the rounding hack is applied in logical order. @@ -190,27 +192,28 @@ static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef for (i = 1; i < count; i++) { bool isLastChar = i == count - 1; renderer = renderers[offset / 2]; - if (renderer != lastRenderer) { - lastRenderer = renderer; - spaceGlyph = renderer->m_spaceGlyph; - // The CoreGraphics interpretation of NSFontAntialiasedIntegerAdvancementsRenderingMode seems - // to be "round each glyph's width to the nearest integer". This is not the same as ATSUI - // does in any of its device-metrics modes. - shouldRound = renderer->platformData().roundsGlyphAdvances(); - if (syntheticBoldPass) - syntheticBoldOffset = FloatToFixed(renderer->m_syntheticBoldOffset); - } float width; if (nextCh == zeroWidthSpace || Font::treatAsZeroWidthSpace(nextCh) && !Font::treatAsSpace(nextCh)) { width = 0; - layoutRecords[i-1].glyphID = spaceGlyph; + layoutRecords[i-1].glyphID = renderer->spaceGlyph(); } else { width = FixedToFloat(layoutRecords[i].realPos - lastNativePos); + if (renderer != lastRenderer && width) { + lastRenderer = renderer; + // The CoreGraphics interpretation of NSFontAntialiasedIntegerAdvancementsRenderingMode seems + // to be "round each glyph's width to the nearest integer". This is not the same as ATSUI + // does in any of its device-metrics modes. + shouldRound = renderer->platformData().roundsGlyphAdvances(); + if (syntheticBoldPass) + syntheticBoldOffset = FloatToFixed(renderer->syntheticBoldOffset()); + if (params->m_fallbackFonts && renderer != params->m_font->primaryFont()) + params->m_fallbackFonts->add(renderer); + } if (shouldRound) width = roundf(width); - width += renderer->m_syntheticBoldOffset; - if (renderer->m_treatAsFixedPitch ? width == renderer->m_spaceWidth : (layoutRecords[i-1].flags & kATSGlyphInfoIsWhiteSpace)) - width = renderer->m_adjustedSpaceWidth; + width += renderer->syntheticBoldOffset(); + if (renderer->pitch() == FixedPitch ? width == renderer->spaceWidth() : (layoutRecords[i-1].flags & kATSGlyphInfoIsWhiteSpace)) + width = renderer->adjustedSpaceWidth(); } lastNativePos = layoutRecords[i].realPos; @@ -258,7 +261,7 @@ static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef if (syntheticBoldOffset) layoutRecords[i-1].realPos += syntheticBoldOffset; else - layoutRecords[i-1].glyphID = spaceGlyph; + layoutRecords[i-1].glyphID = renderer->spaceGlyph(); } layoutRecords[i].realPos = FloatToFixed(lastAdjustedPos); } @@ -460,7 +463,7 @@ void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* g } } else m_fonts[i] = r; - if (m_fonts[i]->m_syntheticBoldOffset) + if (m_fonts[i]->syntheticBoldOffset()) m_hasSyntheticBold = true; } substituteOffset += substituteLength; @@ -570,12 +573,12 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRun& run, graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const { if (run.length() == 0) return 0; - ATSULayoutParameters params(run); + ATSULayoutParameters params(run, fallbackFonts); params.initialize(this); OSStatus status; diff --git a/WebCore/platform/graphics/mac/FontMacCoreText.cpp b/WebCore/platform/graphics/mac/FontMacCoreText.cpp index 5fb9d5d..9dffc7a 100644 --- a/WebCore/platform/graphics/mac/FontMacCoreText.cpp +++ b/WebCore/platform/graphics/mac/FontMacCoreText.cpp @@ -86,9 +86,9 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F drawGlyphBuffer(context, glyphBuffer, run, startPoint); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const { - CoreTextController controller(this, run, true); + CoreTextController controller(this, run, true, fallbackFonts); return controller.totalWidth(); } diff --git a/WebCore/platform/graphics/mac/FontPlatformData.h b/WebCore/platform/graphics/mac/FontPlatformData.h index e911867..1b7b884 100644 --- a/WebCore/platform/graphics/mac/FontPlatformData.h +++ b/WebCore/platform/graphics/mac/FontPlatformData.h @@ -82,6 +82,8 @@ struct FontPlatformData { bool isHashTableDeletedValue() const { return m_font == hashTableDeletedFontValue(); } float size() const { return m_size; } + bool syntheticBold() const { return m_syntheticBold; } + bool syntheticOblique() const { return m_syntheticOblique; } bool m_syntheticBold; bool m_syntheticOblique; diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm index 4e11602..2404319 100644 --- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm +++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm @@ -96,27 +96,28 @@ static NSColor* createPatternColor(NSString* name, NSColor* defaultColor, bool& color = defaultColor; return color; } - + +// WebKit on Mac is a standard platform component, so it must use the standard platform artwork for underline. void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, int width, bool grammar) { if (paintingDisabled()) return; - // These are the same for misspelling or bad grammar + // These are the same for misspelling or bad grammar. int patternHeight = cMisspellingLineThickness; int patternWidth = cMisspellingLinePatternWidth; bool usingDot; NSColor *patternColor; if (grammar) { - // Constants for grammar pattern color + // Constants for grammar pattern color. static bool usingDotForGrammar = false; DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, grammarPatternColor, (createPatternColor(@"GrammarDot", [NSColor greenColor], usingDotForGrammar))); usingDot = usingDotForGrammar; patternColor = grammarPatternColor.get(); } else { - // Constants for spelling pattern color + // Constants for spelling pattern color. static bool usingDotForSpelling = false; DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, spellingPatternColor, (createPatternColor(@"SpellingDot", [NSColor redColor], usingDotForSpelling))); @@ -141,7 +142,7 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, // FIXME: This code should not be using wkSetPatternPhaseInUserSpace, as this approach is wrong // for transforms. - // Draw underline + // Draw underline. NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; CGContextRef context = (CGContextRef)[currentContext graphicsPort]; CGContextSaveGState(context); diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h index 3a692d3..50138d5 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h @@ -117,9 +117,8 @@ private: bool requiresTiledLayer(const FloatSize&) const; void swapFromOrToTiledLayer(bool useTiledLayer); - void setHasContentsLayer(bool); void setContentsLayer(WebLayer*); - void setContentsLayerFlipped(bool); + WebLayer* contentsLayer() const { return m_contentsLayer.get(); } RetainPtr<WebLayer> m_layer; RetainPtr<WebLayer> m_transformLayer; diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index f3f2d7f..f361437 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -271,9 +271,9 @@ static bool forceSoftwareAnimation() return forceSoftwareAnimation; } -bool GraphicsLayer::graphicsContextsFlipped() +GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoordinatesOrientation() { - return true; + return CompositingCoordinatesBottomUp; } #ifndef NDEBUG @@ -746,8 +746,10 @@ void GraphicsLayerCA::setDrawsContent(bool drawsContent) swapFromOrToTiledLayer(needTiledLayer); BEGIN_BLOCK_OBJC_EXCEPTIONS - // Clobber any existing content. If necessary, CA will create backing store on the next display. - [m_layer.get() setContents:nil]; + if (m_drawsContent) + [m_layer.get() setNeedsDisplay]; + else + [m_layer.get() setContents:nil]; #ifndef NDEBUG updateDebugIndicators(); @@ -761,7 +763,14 @@ void GraphicsLayerCA::setBackgroundColor(const Color& color, const Animation* tr GraphicsLayer::setBackgroundColor(color, transition, beginTime); BEGIN_BLOCK_OBJC_EXCEPTIONS - setHasContentsLayer(true); + + if (!m_contentsLayer.get()) { + WebLayer* colorLayer = [WebLayer layer]; +#ifndef NDEBUG + [colorLayer setName:@"Color Layer"]; +#endif + setContentsLayer(colorLayer); + } if (transition && !transition->isEmptyOrZeroDuration()) { CALayer* presLayer = [m_contentsLayer.get() presentationLayer]; @@ -777,7 +786,6 @@ void GraphicsLayerCA::setBackgroundColor(const Color& color, const Animation* tr CGColorRelease(bgColor); } else { removeAllAnimationsForProperty(AnimatedPropertyBackgroundColor); - setHasContentsLayer(true); setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor); } @@ -787,7 +795,7 @@ void GraphicsLayerCA::setBackgroundColor(const Color& color, const Animation* tr void GraphicsLayerCA::clearBackgroundColor() { if (!m_contentLayerForImageOrVideo) - setHasContentsLayer(false); + setContentsLayer(0); else clearLayerBackgroundColor(m_contentsLayer.get()); } @@ -1082,35 +1090,27 @@ bool GraphicsLayerCA::animateFloat(AnimatedPropertyID property, const FloatValue void GraphicsLayerCA::setContentsToImage(Image* image) { if (image) { - setHasContentsLayer(true); - - // FIXME: is image flipping really a property of the graphics context? - bool needToFlip = GraphicsLayer::graphicsContextsFlipped(); - CGPoint anchorPoint = needToFlip ? CGPointMake(0.0f, 1.0f) : CGPointZero; - BEGIN_BLOCK_OBJC_EXCEPTIONS { - CGImageRef theImage = image->nativeImageForCurrentFrame(); + if (!m_contentsLayer.get()) { + WebLayer* imageLayer = [WebLayer layer]; +#ifndef NDEBUG + [imageLayer setName:@"Image Layer"]; +#endif + setContentsLayer(imageLayer); + } + // FIXME: maybe only do trilinear if the image is being scaled down, // but then what if the layer size changes? -#if HAVE_MODERN_QUARTZCORE +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear]; #endif - if (needToFlip) { - CATransform3D flipper = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, -1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f}; - [m_contentsLayer.get() setTransform:flipper]; - } - - [m_contentsLayer.get() setAnchorPoint:anchorPoint]; + CGImageRef theImage = image->nativeImageForCurrentFrame(); [m_contentsLayer.get() setContents:(id)theImage]; } END_BLOCK_OBJC_EXCEPTIONS } else - setHasContentsLayer(false); + setContentsLayer(0); m_contentLayerForImageOrVideo = (image != 0); } @@ -1124,7 +1124,7 @@ void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer) void GraphicsLayerCA::clearContents() { if (m_contentLayerForImageOrVideo) { - setHasContentsLayer(false); + setContentsLayer(0); m_contentLayerForImageOrVideo = false; } } @@ -1431,7 +1431,7 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer) [tiledLayer setLevelsOfDetail:1]; [tiledLayer setLevelsOfDetailBias:0]; - if (GraphicsLayer::graphicsContextsFlipped()) + if (GraphicsLayer::compositingCoordinatesOrientation() == GraphicsLayer::CompositingCoordinatesBottomUp) [tiledLayer setContentsGravity:@"bottomLeft"]; else [tiledLayer setContentsGravity:@"topLeft"]; @@ -1476,24 +1476,6 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer) #endif } -void GraphicsLayerCA::setHasContentsLayer(bool hasLayer) -{ - BEGIN_BLOCK_OBJC_EXCEPTIONS - - if (hasLayer && !m_contentsLayer) { - // create the inner layer - WebLayer* contentsLayer = [WebLayer layer]; -#ifndef NDEBUG - [contentsLayer setName:@"Contents Layer"]; -#endif - setContentsLayer(contentsLayer); - - } else if (!hasLayer && m_contentsLayer) - setContentsLayer(0); - - END_BLOCK_OBJC_EXCEPTIONS -} - void GraphicsLayerCA::setContentsLayer(WebLayer* contentsLayer) { if (contentsLayer == m_contentsLayer) @@ -1511,14 +1493,26 @@ void GraphicsLayerCA::setContentsLayer(WebLayer* contentsLayer) [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]]; m_contentsLayer.adoptNS([contentsLayer retain]); - [m_contentsLayer.get() setAnchorPoint:CGPointZero]; - [m_layer.get() addSublayer:m_contentsLayer.get()]; - updateContentsRect(); + bool needToFlip = GraphicsLayer::compositingCoordinatesOrientation() == GraphicsLayer::CompositingCoordinatesBottomUp; + CGPoint anchorPoint = needToFlip ? CGPointMake(0.0f, 1.0f) : CGPointZero; - // Set contents to nil if the layer does not draw its own content. - if (m_client && !drawsContent()) - [m_layer.get() setContents:nil]; + // If the layer world is flipped, we need to un-flip the contents layer + if (needToFlip) { + CATransform3D flipper = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + [m_contentsLayer.get() setTransform:flipper]; + } + [m_contentsLayer.get() setAnchorPoint:anchorPoint]; + + // Insert the content layer first. Video elements require this, because they have + // shadow content that must display in front of the video. + [m_layer.get() insertSublayer:m_contentsLayer.get() atIndex:0]; + + updateContentsRect(); #ifndef NDEBUG if (showDebugBorders()) { diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h index 677c31a..f90f258 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h @@ -30,6 +30,7 @@ #include "MediaPlayerPrivate.h" #include "Timer.h" +#include "FloatSize.h" #include <wtf/RetainPtr.h> #ifdef __OBJC__ @@ -127,6 +128,8 @@ private: float maxTimeLoaded() const; void disableUnsupportedTracks(); + void sawUnsupportedTracks(); + void cacheMovieScale(); bool metaDataAvailable() const { return m_qtMovie && m_readyState >= MediaPlayer::HaveMetadata; } MediaPlayer* m_player; @@ -142,7 +145,10 @@ private: bool m_isStreaming; bool m_visible; IntRect m_rect; + FloatSize m_scaleFactor; unsigned m_enabledTrackCount; + unsigned m_totalTrackCount; + bool m_hasUnsupportedTracks; float m_duration; #if DRAW_FRAME_RATE int m_frameCountWhilePlaying; diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index 74a9ff9..dd41ed3 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -37,6 +37,7 @@ #import "FrameView.h" #import "GraphicsContext.h" #import "KURL.h" +#import "MIMETypeRegistry.h" #import "SoftLinking.h" #import "WebCoreSystemInterface.h" #import <QTKit/QTKit.h> @@ -67,6 +68,7 @@ SOFT_LINK(QTKit, QTMakeTime, QTTime, (long long timeValue, long timeScale), (tim SOFT_LINK_CLASS(QTKit, QTMovie) SOFT_LINK_CLASS(QTKit, QTMovieView) +SOFT_LINK_POINTER(QTKit, QTTrackMediaTypeAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMediaTypeAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMediaTypeBase, NSString *) SOFT_LINK_POINTER(QTKit, QTMediaTypeMPEG, NSString *) @@ -81,6 +83,7 @@ SOFT_LINK_POINTER(QTKit, QTMovieIsActiveAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieLoadStateAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieLoadStateDidChangeNotification, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieNaturalSizeAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieCurrentSizeAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMoviePreventExternalURLLinksAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieRateDidChangeNotification, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieSizeDidChangeNotification, NSString *) @@ -90,10 +93,15 @@ SOFT_LINK_POINTER(QTKit, QTMovieURLAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieVolumeDidChangeNotification, NSString *) SOFT_LINK_POINTER(QTKit, QTSecurityPolicyNoCrossSiteAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTVideoRendererWebKitOnlyNewImageAvailableNotification, NSString *) +#ifndef BUILDING_ON_TIGER +SOFT_LINK_POINTER(QTKit, QTMovieApertureModeClean, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieApertureModeAttribute, NSString *) +#endif #define QTMovie getQTMovieClass() #define QTMovieView getQTMovieViewClass() +#define QTTrackMediaTypeAttribute getQTTrackMediaTypeAttribute() #define QTMediaTypeAttribute getQTMediaTypeAttribute() #define QTMediaTypeBase getQTMediaTypeBase() #define QTMediaTypeMPEG getQTMediaTypeMPEG() @@ -108,6 +116,7 @@ SOFT_LINK_POINTER(QTKit, QTVideoRendererWebKitOnlyNewImageAvailableNotification, #define QTMovieLoadStateAttribute getQTMovieLoadStateAttribute() #define QTMovieLoadStateDidChangeNotification getQTMovieLoadStateDidChangeNotification() #define QTMovieNaturalSizeAttribute getQTMovieNaturalSizeAttribute() +#define QTMovieCurrentSizeAttribute getQTMovieCurrentSizeAttribute() #define QTMoviePreventExternalURLLinksAttribute getQTMoviePreventExternalURLLinksAttribute() #define QTMovieRateDidChangeNotification getQTMovieRateDidChangeNotification() #define QTMovieSizeDidChangeNotification getQTMovieSizeDidChangeNotification() @@ -117,6 +126,10 @@ SOFT_LINK_POINTER(QTKit, QTVideoRendererWebKitOnlyNewImageAvailableNotification, #define QTMovieVolumeDidChangeNotification getQTMovieVolumeDidChangeNotification() #define QTSecurityPolicyNoCrossSiteAttribute getQTSecurityPolicyNoCrossSiteAttribute() #define QTVideoRendererWebKitOnlyNewImageAvailableNotification getQTVideoRendererWebKitOnlyNewImageAvailableNotification() +#ifndef BUILDING_ON_TIGER +#define QTMovieApertureModeClean getQTMovieApertureModeClean() +#define QTMovieApertureModeAttribute getQTMovieApertureModeAttribute() +#endif // Older versions of the QTKit header don't have these constants. #if !defined QTKIT_VERSION_MAX_ALLOWED || QTKIT_VERSION_MAX_ALLOWED <= QTKIT_VERSION_7_0 @@ -184,7 +197,10 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_isStreaming(false) , m_visible(false) , m_rect() + , m_scaleFactor(1, 1) , m_enabledTrackCount(0) + , m_totalTrackCount(0) + , m_hasUnsupportedTracks(false) , m_duration(-1.0f) #if DRAW_FRAME_RATE , m_frameCountWhilePlaying(0) @@ -221,10 +237,15 @@ void MediaPlayerPrivate::createQTMovie(const String& url) [NSNumber numberWithBool:YES], QTMoviePreventExternalURLLinksAttribute, [NSNumber numberWithBool:YES], QTSecurityPolicyNoCrossSiteAttribute, [NSNumber numberWithBool:NO], QTMovieAskUnresolvedDataRefsAttribute, - [NSNumber numberWithBool:YES], @"QTMovieOpenForPlaybackAttribute", // FIXME: Use defined attribute when required version of QT supports this attribute +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + [NSNumber numberWithBool:YES], @"QTMovieOpenForPlaybackAttribute", +#endif +#ifndef BUILDING_ON_TIGER + QTMovieApertureModeClean, QTMovieApertureModeAttribute, +#endif nil]; - NSError* error = nil; + NSError *error = nil; m_qtMovie.adoptNS([[QTMovie alloc] initWithAttributes:movieAttributes error:&error]); // FIXME: Find a proper way to detect streaming content. @@ -239,6 +260,17 @@ void MediaPlayerPrivate::createQTMovie(const String& url) selector:@selector(loadStateChanged:) name:QTMovieLoadStateDidChangeNotification object:m_qtMovie.get()]; + + // In updateState(), we track when maxTimeLoaded() == duration(). + // In newer version of QuickTime, a notification is emitted when maxTimeLoaded changes. + // In older version of QuickTime, QTMovieLoadStateDidChangeNotification be fired. + if (NSString *maxTimeLoadedChangeNotification = wkQTMovieMaxTimeLoadedChangeNotification()) { + [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get() + selector:@selector(loadStateChanged:) + name:maxTimeLoadedChangeNotification + object:m_qtMovie.get()]; + } + [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get() selector:@selector(rateChanged:) name:QTMovieRateDidChangeNotification @@ -545,7 +577,16 @@ IntSize MediaPlayerPrivate::naturalSize() const { if (!metaDataAvailable()) return IntSize(); - return IntSize([[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]); + + // In spite of the name of this method, return QTMovieNaturalSizeAttribute transformed by the + // initial movie scale because the spec says intrinsic size is: + // + // ... the dimensions of the resource in CSS pixels after taking into account the resource's + // dimensions, aspect ratio, clean aperture, resolution, and so forth, as defined for the + // format used by the resource + + NSSize naturalSize = [[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]; + return IntSize(naturalSize.width * m_scaleFactor.width(), naturalSize.height * m_scaleFactor.height()); } bool MediaPlayerPrivate::hasVideo() const @@ -586,8 +627,14 @@ float MediaPlayerPrivate::maxTimeBuffered() const float MediaPlayerPrivate::maxTimeSeekable() const { + if (!metaDataAvailable()) + return 0; + // infinite duration means live stream - return isinf(duration()) ? 0 : maxTimeLoaded(); + if (isinf(duration())) + return 0; + + return wkQTMovieMaxTimeSeekable(m_qtMovie.get()); } float MediaPlayerPrivate::maxTimeLoaded() const @@ -629,6 +676,31 @@ void MediaPlayerPrivate::cancelLoad() updateStates(); } +void MediaPlayerPrivate::cacheMovieScale() +{ + NSSize initialSize = NSZeroSize; + NSSize naturalSize = [[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]; + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + // QTMovieCurrentSizeAttribute is not allowed with instances of QTMovie that have been + // opened with QTMovieOpenForPlaybackAttribute, so ask for the display transform attribute instead. + NSAffineTransform *displayTransform = [m_qtMovie.get() attributeForKey:@"QTMoviePreferredTransformAttribute"]; + if (displayTransform) + initialSize = [displayTransform transformSize:naturalSize]; + else { + initialSize.width = naturalSize.width; + initialSize.height = naturalSize.height; + } +#else + initialSize = [[m_qtMovie.get() attributeForKey:QTMovieCurrentSizeAttribute] sizeValue]; +#endif + + if (naturalSize.width) + m_scaleFactor.setWidth(initialSize.width / naturalSize.width); + if (naturalSize.height) + m_scaleFactor.setHeight(initialSize.height / naturalSize.height); +} + void MediaPlayerPrivate::updateStates() { MediaPlayer::NetworkState oldNetworkState = m_networkState; @@ -636,18 +708,37 @@ void MediaPlayerPrivate::updateStates() long loadState = m_qtMovie ? [[m_qtMovie.get() attributeForKey:QTMovieLoadStateAttribute] longValue] : static_cast<long>(QTMovieLoadStateError); - if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata && !m_player->inMediaDocument()) { + if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) { disableUnsupportedTracks(); - if (!m_enabledTrackCount) + if (m_player->inMediaDocument()) { + if (!m_enabledTrackCount || m_enabledTrackCount != m_totalTrackCount) { + // This is a type of media that we do not handle directly with a <video> + // element, likely streamed media or QuickTime VR. Tell the MediaPlayerClient + // that we noticed. + sawUnsupportedTracks(); + return; + } + } else if (!m_enabledTrackCount) { loadState = QTMovieLoadStateError; + } + + if (loadState != QTMovieLoadStateError) + cacheMovieScale(); } - if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) { + BOOL completelyLoaded = !m_isStreaming && (loadState >= QTMovieLoadStateComplete); + + // Note: QT indicates that we are fully loaded with QTMovieLoadStateComplete. + // However newer versions of QT do not, so we check maxTimeLoaded against duration. + if (!completelyLoaded && !m_isStreaming && metaDataAvailable()) + completelyLoaded = maxTimeLoaded() == duration(); + + if (completelyLoaded) { // "Loaded" is reserved for fully buffered movies, never the case when streaming m_networkState = MediaPlayer::Loaded; m_readyState = MediaPlayer::HaveEnoughData; } else if (loadState >= QTMovieLoadStatePlaythroughOK) { - m_readyState = MediaPlayer::HaveFutureData; + m_readyState = MediaPlayer::HaveEnoughData; m_networkState = MediaPlayer::Loading; } else if (loadState >= QTMovieLoadStatePlayable) { // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967> @@ -657,11 +748,17 @@ void MediaPlayerPrivate::updateStates() m_readyState = MediaPlayer::HaveMetadata; m_networkState = MediaPlayer::Loading; } else if (loadState > QTMovieLoadStateError) { - m_readyState = MediaPlayer::HaveNothing; + m_readyState = MediaPlayer::HaveNothing; m_networkState = MediaPlayer::Loading; } else { - float loaded = maxTimeLoaded(); + if (m_player->inMediaDocument()) { + // Something went wrong in the loading of media within a standalone file. + // This can occur with chained refmovies pointing to streamed media. + sawUnsupportedTracks(); + return; + } + float loaded = maxTimeLoaded(); if (!loaded) m_readyState = MediaPlayer::HaveNothing; @@ -684,7 +781,7 @@ void MediaPlayerPrivate::updateStates() if (m_readyState != oldReadyState) m_player->readyStateChanged(); - if (loadState >= QTMovieLoadStateLoaded && oldReadyState < MediaPlayer::HaveMetadata && m_player->visible()) + if (loadState >= QTMovieLoadStateLoaded && (!m_qtMovieView && !m_qtVideoRenderer) && m_player->visible()) setUpVideoRendering(); if (loadState >= QTMovieLoadStateLoaded) { @@ -699,28 +796,39 @@ void MediaPlayerPrivate::updateStates() void MediaPlayerPrivate::loadStateChanged() { - updateStates(); + if (!m_hasUnsupportedTracks) + updateStates(); } void MediaPlayerPrivate::rateChanged() { + if (m_hasUnsupportedTracks) + return; + updateStates(); m_player->rateChanged(); } void MediaPlayerPrivate::sizeChanged() { - m_player->sizeChanged(); + if (!m_hasUnsupportedTracks) + m_player->sizeChanged(); } void MediaPlayerPrivate::timeChanged() { + if (m_hasUnsupportedTracks) + return; + updateStates(); m_player->timeChanged(); } void MediaPlayerPrivate::didEnd() { + if (m_hasUnsupportedTracks) + return; + m_startedPlaying = false; #if DRAW_FRAME_RATE m_timeStoppedPlaying = [NSDate timeIntervalSinceReferenceDate]; @@ -729,22 +837,15 @@ void MediaPlayerPrivate::didEnd() m_player->timeChanged(); } -void MediaPlayerPrivate::setSize(const IntSize& size) +void MediaPlayerPrivate::setSize(const IntSize&) { - if (!m_qtMovieView) - return; - - m_rect.setSize(size); - if (m_player->inMediaDocument()) - // We need the QTMovieView to be placed in the proper location for document mode. - [m_qtMovieView.get() setFrame:m_rect]; - else { - // We don't really need the QTMovieView in any specific location so let's just get it out of the way - // where it won't intercept events or try to bring up the context menu. - IntRect farAwayButCorrectSize(m_rect); - farAwayButCorrectSize.move(-1000000, -1000000); - [m_qtMovieView.get() setFrame:farAwayButCorrectSize]; - } + // Don't resize the view now because [view setFrame] also resizes the movie itself, and because + // the renderer calls this function immediately when we report a size change (QTMovieSizeDidChangeNotification) + // we can get into a feedback loop observing the size change and resetting the size, and this can cause + // QuickTime to miss resetting a movie's size when the media size changes (as happens with an rtsp movie + // once the rtsp server sends the track sizes). Instead we remember the size passed to paint() and resize + // the view when it changes. + // <rdar://problem/6336092> REGRESSION: rtsp movie does not resize correctly } void MediaPlayerPrivate::setVisible(bool b) @@ -761,6 +862,9 @@ void MediaPlayerPrivate::setVisible(bool b) void MediaPlayerPrivate::repaint() { + if (m_hasUnsupportedTracks) + return; + #if DRAW_FRAME_RATE if (m_startedPlaying) { m_frameCountWhilePlaying++; @@ -775,7 +879,7 @@ void MediaPlayerPrivate::repaint() void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) { - if (context->paintingDisabled()) + if (context->paintingDisabled() || m_hasUnsupportedTracks) return; NSView *view = m_qtMovieView.get(); id qtVideoRenderer = m_qtVideoRenderer.get(); @@ -802,12 +906,28 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) [(id<WebKitVideoRenderingDetails>)qtVideoRenderer drawInRect:paintRect]; [NSGraphicsContext restoreGraphicsState]; } else { - if (m_player->inMediaDocument() && r != m_rect) { - // the QTMovieView needs to be placed in the proper location for document mode - m_rect = r; - [view setFrame:m_rect]; + if (m_rect != r) { + m_rect = r; + if (m_player->inMediaDocument()) { + // the QTMovieView needs to be placed in the proper location for document mode + [view setFrame:m_rect]; + } + else { + // We don't really need the QTMovieView in any specific location so let's just get it out of the way + // where it won't intercept events or try to bring up the context menu. + IntRect farAwayButCorrectSize(m_rect); + farAwayButCorrectSize.move(-1000000, -1000000); + [view setFrame:farAwayButCorrectSize]; + } } - [view displayRectIgnoringOpacity:paintRect inContext:newContext]; + + if (m_player->inMediaDocument()) { + // If we're using a QTMovieView in a media document, the view may get layer-backed. AppKit won't update + // the layer hosting correctly if we call displayRectIgnoringOpacity:inContext:, so use displayRectIgnoringOpacity: + // in this case. See <rdar://problem/6702882>. + [view displayRectIgnoringOpacity:paintRect]; + } else + [view displayRectIgnoringOpacity:paintRect inContext:newContext]; } #if DRAW_FRAME_RATE @@ -839,25 +959,57 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) [m_objcObserver.get() setDelayCallbacks:NO]; } -static HashSet<String> mimeTypeCache() +static void addFileTypesToCache(NSArray * fileTypes, HashSet<String> &cache) +{ + int count = [fileTypes count]; + for (int n = 0; n < count; n++) { + CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]); + RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL)); + if (!uti) + continue; + RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType)); + + // UTI types are missing many media related MIME types supported by QTKit, see rdar://6434168, + // and not all third party movie importers register their types, so if we didn't find a type for + // this extension look it up in the hard coded table in the MIME type regsitry. + if (!mime) { + // -movieFileTypes: returns both file extensions and OSTypes. The later are surrounded by single + // quotes, eg. 'MooV', so don't bother looking at those. + if (CFStringGetCharacterAtIndex(ext, 0) != '\'') { + String mediaType = MIMETypeRegistry::getMediaMIMETypeForExtension(String(ext)); + if (!mediaType.isEmpty()) + mime.adoptCF(mediaType.createCFString()); + } + } + if (!mime) + continue; + cache.add(mime.get()); + } +} + +static HashSet<String> mimeCommonTypesCache() { DEFINE_STATIC_LOCAL(HashSet<String>, cache, ()); static bool typeListInitialized = false; if (!typeListInitialized) { + typeListInitialized = true; NSArray* fileTypes = [QTMovie movieFileTypes:QTIncludeCommonTypes]; - int count = [fileTypes count]; - for (int n = 0; n < count; n++) { - CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]); - RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL)); - if (!uti) - continue; - RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType)); - if (!mime) - continue; - cache.add(mime.get()); - } + addFileTypesToCache(fileTypes, cache); + } + + return cache; +} + +static HashSet<String> mimeModernTypesCache() +{ + DEFINE_STATIC_LOCAL(HashSet<String>, cache, ()); + static bool typeListInitialized = false; + + if (!typeListInitialized) { typeListInitialized = true; + NSArray* fileTypes = [QTMovie movieFileTypes:(QTMovieFileTypeOptions)wkQTIncludeOnlyModernMediaFileTypes()]; + addFileTypesToCache(fileTypes, cache); } return cache; @@ -865,14 +1017,21 @@ static HashSet<String> mimeTypeCache() void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) { - types = mimeTypeCache(); + // Note: this method starts QTKitServer if it isn't already running when in 64-bit because it has to return the list + // of every MIME type supported by QTKit. + types = mimeCommonTypesCache(); } MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) { - // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an - // extended MIME type yet - return mimeTypeCache().contains(type) ? (codecs && !codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported; + // Only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an + // extended MIME type yet. + + // We check the "modern" type cache first, as it doesn't require QTKitServer to start. + if (mimeModernTypesCache().contains(type) || mimeCommonTypesCache().contains(type)) + return (codecs && !codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported); + + return MediaPlayer::IsNotSupported; } bool MediaPlayerPrivate::isAvailable() @@ -900,6 +1059,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks() { if (!m_qtMovie) { m_enabledTrackCount = 0; + m_totalTrackCount = 0; return; } @@ -911,15 +1071,19 @@ void MediaPlayerPrivate::disableUnsupportedTracks() allowedTrackTypes->add(QTMediaTypeText); allowedTrackTypes->add(QTMediaTypeBase); allowedTrackTypes->add(QTMediaTypeMPEG); - allowedTrackTypes->add("clcp"); - allowedTrackTypes->add("sbtl"); + allowedTrackTypes->add("clcp"); // Closed caption + allowedTrackTypes->add("sbtl"); // Subtitle + allowedTrackTypes->add("odsm"); // MPEG-4 object descriptor stream + allowedTrackTypes->add("sdsm"); // MPEG-4 scene description stream + allowedTrackTypes->add("tmcd"); // timecode + allowedTrackTypes->add("tc64"); // timcode-64 } NSArray *tracks = [m_qtMovie.get() tracks]; - unsigned trackCount = [tracks count]; - m_enabledTrackCount = trackCount; - for (unsigned trackIndex = 0; trackIndex < trackCount; trackIndex++) { + m_totalTrackCount = [tracks count]; + m_enabledTrackCount = m_totalTrackCount; + for (unsigned trackIndex = 0; trackIndex < m_totalTrackCount; trackIndex++) { // Grab the track at the current index. If there isn't one there, then // we can move onto the next one. QTTrack *track = [tracks objectAtIndex:trackIndex]; @@ -931,24 +1095,18 @@ void MediaPlayerPrivate::disableUnsupportedTracks() if (![track isEnabled]) continue; - // Grab the track's media. We're going to check to see if we need to - // disable the tracks. They could be unsupported. - QTMedia *trackMedia = [track media]; - if (!trackMedia) - continue; - - // Grab the media type for this track. - NSString *mediaType = [trackMedia attributeForKey:QTMediaTypeAttribute]; + // Get the track's media type. + NSString *mediaType = [track attributeForKey:QTTrackMediaTypeAttribute]; if (!mediaType) continue; - + // Test whether the media type is in our white list. if (!allowedTrackTypes->contains(mediaType)) { // If this track type is not allowed, then we need to disable it. [track setEnabled:NO]; --m_enabledTrackCount; } - + // Disable chapter tracks. These are most likely to lead to trouble, as // they will be composited under the video tracks, forcing QT to do extra // work. @@ -982,6 +1140,12 @@ void MediaPlayerPrivate::disableUnsupportedTracks() } } +void MediaPlayerPrivate::sawUnsupportedTracks() +{ + m_hasUnsupportedTracks = true; + m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player); +} + } @implementation WebCoreMovieObserver diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index a3c10fa..cdde7cf 100644 --- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -58,7 +58,7 @@ static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return x * (c static bool initFontData(SimpleFontData* fontData) { - if (!fontData->m_font.cgFont()) + if (!fontData->platformData().cgFont()) return false; #ifdef BUILDING_ON_TIGER @@ -66,7 +66,7 @@ static bool initFontData(SimpleFontData* fontData) if (ATSUCreateStyle(&fontStyle) != noErr) return false; - ATSUFontID fontId = fontData->m_font.m_atsuFontID; + ATSUFontID fontId = fontData->platformData().m_atsuFontID; if (!fontId) { ATSUDisposeStyle(fontStyle); return false; @@ -153,7 +153,7 @@ void SimpleFontData::platformInit() m_shapesArabic = false; #endif - m_syntheticBoldOffset = m_font.m_syntheticBold ? 1.0f : 0.f; + m_syntheticBoldOffset = m_platformData.m_syntheticBold ? 1.0f : 0.f; bool failedSetup = false; if (!initFontData(this)) { @@ -165,7 +165,7 @@ void SimpleFontData::platformInit() // It overrides the normal "Times" family font. // It also appears to have a corrupt regular variant. NSString *fallbackFontFamily; - if ([[m_font.font() familyName] isEqual:@"Times"]) + if ([[m_platformData.font() familyName] isEqual:@"Times"]) fallbackFontFamily = @"Times New Roman"; else fallbackFontFamily = webFallbackFontFamily(); @@ -173,12 +173,12 @@ void SimpleFontData::platformInit() // Try setting up the alternate font. // This is a last ditch effort to use a substitute font when something has gone wrong. #if !ERROR_DISABLED - RetainPtr<NSFont> initialFont = m_font.font(); + RetainPtr<NSFont> initialFont = m_platformData.font(); #endif - if (m_font.font()) - m_font.setFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toFamily:fallbackFontFamily]); + if (m_platformData.font()) + m_platformData.setFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toFamily:fallbackFontFamily]); else - m_font.setFont([NSFont fontWithName:fallbackFontFamily size:m_font.size()]); + m_platformData.setFont([NSFont fontWithName:fallbackFontFamily size:m_platformData.size()]); #if !ERROR_DISABLED NSString *filePath = pathFromFont(initialFont.get()); if (!filePath) @@ -188,7 +188,7 @@ void SimpleFontData::platformInit() if ([fallbackFontFamily isEqual:@"Times New Roman"]) { // OK, couldn't setup Times New Roman as an alternate to Times, fallback // on the system font. If this fails we have no alternative left. - m_font.setFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toFamily:webFallbackFontFamily()]); + m_platformData.setFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toFamily:webFallbackFontFamily()]); if (!initFontData(this)) { // We tried, Times, Times New Roman, and the system font. No joy. We have to give up. LOG_ERROR("unable to initialize with font %@ at %@", initialFont.get(), filePath); @@ -203,14 +203,14 @@ void SimpleFontData::platformInit() // Report the problem. LOG_ERROR("Corrupt font detected, using %@ in place of %@ located at \"%@\".", - [m_font.font() familyName], [initialFont.get() familyName], filePath); + [m_platformData.font() familyName], [initialFont.get() familyName], filePath); } // If all else fails, try to set up using the system font. // This is probably because Times and Times New Roman are both unavailable. if (failedSetup) { - m_font.setFont([NSFont systemFontOfSize:[m_font.font() pointSize]]); - LOG_ERROR("failed to set up font, using system font %s", m_font.font()); + m_platformData.setFont([NSFont systemFontOfSize:[m_platformData.font() pointSize]]); + LOG_ERROR("failed to set up font, using system font %s", m_platformData.font()); initFontData(this); } @@ -218,15 +218,15 @@ void SimpleFontData::platformInit() int iDescent; int iLineGap; #ifdef BUILDING_ON_TIGER - wkGetFontMetrics(m_font.cgFont(), &iAscent, &iDescent, &iLineGap, &m_unitsPerEm); + wkGetFontMetrics(m_platformData.cgFont(), &iAscent, &iDescent, &iLineGap, &m_unitsPerEm); #else - iAscent = CGFontGetAscent(m_font.cgFont()); - iDescent = CGFontGetDescent(m_font.cgFont()); - iLineGap = CGFontGetLeading(m_font.cgFont()); - m_unitsPerEm = CGFontGetUnitsPerEm(m_font.cgFont()); + iAscent = CGFontGetAscent(m_platformData.cgFont()); + iDescent = CGFontGetDescent(m_platformData.cgFont()); + iLineGap = CGFontGetLeading(m_platformData.cgFont()); + m_unitsPerEm = CGFontGetUnitsPerEm(m_platformData.cgFont()); #endif - float pointSize = m_font.m_size; + float pointSize = m_platformData.m_size; float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize; float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize; float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize; @@ -236,7 +236,7 @@ void SimpleFontData::platformInit() // web standard. The AppKit adjustment of 20% is too big and is // incorrectly added to line spacing, so we use a 15% adjustment instead // and add it to the ascent. - NSString *familyName = [m_font.font() familyName]; + NSString *familyName = [m_platformData.font() familyName]; if ([familyName isEqualToString:@"Times"] || [familyName isEqualToString:@"Helvetica"] || [familyName isEqualToString:@"Courier"]) fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f); else if ([familyName isEqualToString:@"Geeza Pro"]) { @@ -264,14 +264,49 @@ void SimpleFontData::platformInit() GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); NSGlyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0; if (xGlyph) { - NSRect xBox = [m_font.font() boundingRectForGlyph:xGlyph]; + NSRect xBox = [m_platformData.font() boundingRectForGlyph:xGlyph]; // Use the maximum of either width or height because "x" is nearly square // and web pages that foolishly use this metric for width will be laid out // poorly if we return an accurate height. Classic case is Times 13 point, // which has an "x" that is 7x6 pixels. m_xHeight = MAX(NSMaxX(xBox), NSMaxY(xBox)); } else - m_xHeight = [m_font.font() xHeight]; + m_xHeight = [m_platformData.font() xHeight]; +} + +void SimpleFontData::platformCharWidthInit() +{ + m_avgCharWidth = 0.f; + + // Calculate avgCharWidth according to http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6OS2.html + // We can try grabbing it out of the OS/2 table or via ATSFontGetHorizontalMetrics, but + // ATSFontGetHorizontalMetrics never seems to return a non-zero value and the OS/2 table + // contains zero for a large number of fonts. + GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); + if (glyphPageZero) { + static int weights[] = { 64, 14, 27, 35, 100, 20, 14, 42, 63, 3, 6, 35, 20, 56, 56, 17, 4, 49, 56, 71, 31, 10, 18, 3, 18, 2, 166 }; + int numGlyphs = 27; + ASSERT(numGlyphs == sizeof(weights) / sizeof(int)); + // Compute the weighted sum of the space character and the lowercase letters in the Latin alphabet. + float sum = 0.f; + int totalWeight = 0; + for (int i = 0; i < numGlyphs; i++) { + Glyph glyph = glyphPageZero->glyphDataForCharacter((i < 26 ? i + 'a' : ' ')).glyph; + if (glyph) { + totalWeight += weights[i]; + sum += widthForGlyph(glyph) * weights[i]; + } + } + if (sum > 0.f && totalWeight > 0) + m_avgCharWidth = sum / totalWeight; + } + + m_maxCharWidth = 0.f; + if (m_platformData.font()) + m_maxCharWidth = [m_platformData.font() maximumAdvancement].width; + + // Fallback to a cross-platform estimate, which will populate these values if they are non-positive. + initCharWidths(); } void SimpleFontData::platformDestroy() @@ -290,13 +325,13 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes { if (!m_smallCapsFontData) { if (isCustomFont()) { - FontPlatformData smallCapsFontData(m_font); + FontPlatformData smallCapsFontData(m_platformData); smallCapsFontData.m_size = smallCapsFontData.m_size * smallCapsFontSizeMultiplier; m_smallCapsFontData = new SimpleFontData(smallCapsFontData, true, false); } else { BEGIN_BLOCK_OBJC_EXCEPTIONS; - float size = [m_font.font() pointSize] * smallCapsFontSizeMultiplier; - FontPlatformData smallCapsFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toSize:size]); + float size = [m_platformData.font() pointSize] * smallCapsFontSizeMultiplier; + FontPlatformData smallCapsFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toSize:size]); // AppKit resets the type information (screen/printer) when you convert a font to a different size. // We have to fix up the font that we're handed back. @@ -304,11 +339,11 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes if (smallCapsFont.font()) { NSFontManager *fontManager = [NSFontManager sharedFontManager]; - NSFontTraitMask fontTraits = [fontManager traitsOfFont:m_font.font()]; + NSFontTraitMask fontTraits = [fontManager traitsOfFont:m_platformData.font()]; - if (m_font.m_syntheticBold) + if (m_platformData.m_syntheticBold) fontTraits |= NSBoldFontMask; - if (m_font.m_syntheticOblique) + if (m_platformData.m_syntheticOblique) fontTraits |= NSItalicFontMask; NSFontTraitMask smallCapsFontTraits = [fontManager traitsOfFont:smallCapsFont.font()]; @@ -326,7 +361,7 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes bool SimpleFontData::containsCharacters(const UChar* characters, int length) const { NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<unichar*>(characters) length:length freeWhenDone:NO]; - NSCharacterSet *set = [[m_font.font() coveredCharacterSet] invertedSet]; + NSCharacterSet *set = [[m_platformData.font() coveredCharacterSet] invertedSet]; bool result = set && [string rangeOfCharacterFromSet:set].location == NSNotFound; [string release]; return result; @@ -334,7 +369,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con void SimpleFontData::determinePitch() { - NSFont* f = m_font.font(); + NSFont* f = m_platformData.font(); // Special case Osaka-Mono. // According to <rdar://problem/3999467>, we should treat Osaka-Mono as fixed pitch. // Note that the AppKit does not report Osaka-Mono as fixed pitch. @@ -356,11 +391,11 @@ void SimpleFontData::determinePitch() float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { - NSFont* font = m_font.font(); - float pointSize = m_font.m_size; + NSFont* font = m_platformData.font(); + float pointSize = m_platformData.m_size; CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize); CGSize advance; - if (!wkGetGlyphTransformedAdvances(m_font.cgFont(), font, &m, &glyph, &advance)) { + if (!wkGetGlyphTransformedAdvances(m_platformData.cgFont(), font, &m, &glyph, &advance)) { LOG_ERROR("Unable to cache glyph widths for %@ %f", [font displayName], pointSize); advance.width = 0; } @@ -374,9 +409,9 @@ void SimpleFontData::checkShapesArabic() const m_checkedShapesArabic = true; - ATSUFontID fontID = m_font.m_atsuFontID; + ATSUFontID fontID = m_platformData.m_atsuFontID; if (!fontID) { - LOG_ERROR("unable to get ATSUFontID for %@", m_font.font()); + LOG_ERROR("unable to get ATSUFontID for %@", m_platformData.font()); return; } @@ -404,7 +439,7 @@ CTFontRef SimpleFontData::getCTFont() const if (getNSFont()) return toCTFontRef(getNSFont()); if (!m_CTFont) - m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_font.cgFont(), m_font.size(), NULL, NULL)); + m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_platformData.cgFont(), m_platformData.size(), NULL, NULL)); return m_CTFont.get(); } diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm index 267b5bc..fad3916 100644 --- a/WebCore/platform/graphics/mac/WebLayer.mm +++ b/WebCore/platform/graphics/mac/WebLayer.mm @@ -32,7 +32,6 @@ #import "GraphicsContext.h" #import "GraphicsLayer.h" #import <QuartzCore/QuartzCore.h> -#import "WebCoreTextRenderer.h" #import <wtf/UnusedParam.h> using namespace WebCore; |