diff options
Diffstat (limited to 'WebCore/platform/graphics')
150 files changed, 2714 insertions, 897 deletions
diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp index 1d97632..2f9412d 100644 --- a/WebCore/platform/graphics/BitmapImage.cpp +++ b/WebCore/platform/graphics/BitmapImage.cpp @@ -95,7 +95,7 @@ void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll) // Animated images >5MB are considered large enough that we'll only hang on // to one frame at a time. static const unsigned cLargeAnimationCutoff = 5242880; - if (frameCount() * frameBytes(m_size) > cLargeAnimationCutoff) + if (m_frames.size() * frameBytes(m_size) > cLargeAnimationCutoff) destroyDecodedData(destroyAll); } diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h index db05d1c..a2de5d7 100644 --- a/WebCore/platform/graphics/BitmapImage.h +++ b/WebCore/platform/graphics/BitmapImage.h @@ -44,11 +44,6 @@ class NSImage; typedef struct HBITMAP__ *HBITMAP; #endif -#if PLATFORM(SGL) -class SkBitmap; -class SkBitmapRef; -#endif - namespace WebCore { struct FrameData; } @@ -146,10 +141,13 @@ public: #endif #if PLATFORM(SGL) -// virtual SkBitmapRef* getBitmap(); virtual void setURL(const String& str); #endif +#if PLATFORM(GTK) + virtual GdkPixbuf* getGdkPixbuf(); +#endif + virtual NativeImagePtr nativeImageForCurrentFrame() { return frameAtIndex(currentFrame()); } protected: diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp index e85ac00..d98b202 100644 --- a/WebCore/platform/graphics/Color.cpp +++ b/WebCore/platform/graphics/Color.cpp @@ -321,6 +321,41 @@ void Color::getRGBA(double& r, double& g, double& b, double& a) const a = alpha() / 255.0; } +void Color::getHSL(double& hue, double& saturation, double& lightness) const +{ + // http://en.wikipedia.org/wiki/HSL_color_space. This is a direct copy of + // the algorithm therein, although it's 360^o based and we end up wanting + // [0...1) based. It's clearer if we stick to 360^o until the end. + double r = static_cast<double>(red()) / 255.0; + double g = static_cast<double>(green()) / 255.0; + double b = static_cast<double>(blue()) / 255.0; + double max = std::max(std::max(r, g), b); + double min = std::min(std::min(r, g), b); + + if (max == min) + hue = 0.0; + else if (max == r) + hue = (60.0 * ((g - b) / (max - min))) + 360.0; + else if (max == g) + hue = (60.0 * ((b - r) / (max - min))) + 120.0; + else + hue = (60.0 * ((r - g) / (max - min))) + 240.0; + + if (hue >= 360.0) + hue -= 360.0; + + // makeRGBAFromHSLA assumes that hue is in [0...1). + hue /= 360.0; + + lightness = 0.5 * (max + min); + if (max == min) + saturation = 0.0; + else if (lightness <= 0.5) + saturation = ((max - min) / (max + min)); + else + saturation = ((max - min) / (2.0 - (max + min))); +} + Color colorFromPremultipliedARGB(unsigned pixelColor) { RGBA32 rgba; diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h index 3c889f9..3b815d2 100644 --- a/WebCore/platform/graphics/Color.h +++ b/WebCore/platform/graphics/Color.h @@ -94,6 +94,7 @@ public: void setRGB(RGBA32 rgb) { m_color = rgb; m_valid = true; } void getRGBA(float& r, float& g, float& b, float& a) const; void getRGBA(double& r, double& g, double& b, double& a) const; + void getHSL(double& h, double& s, double& l) const; Color light() const; Color dark() const; diff --git a/WebCore/platform/graphics/FloatQuad.cpp b/WebCore/platform/graphics/FloatQuad.cpp index a32d8ab..427230d 100644 --- a/WebCore/platform/graphics/FloatQuad.cpp +++ b/WebCore/platform/graphics/FloatQuad.cpp @@ -46,6 +46,34 @@ static inline float max4(float a, float b, float c, float d) return max(max(a, b), max(c, d)); } +inline float dot(const FloatSize& a, const FloatSize& b) +{ + return a.width() * b.width() + a.height() * b.height(); +} + +inline bool isPointInTriangle(const FloatPoint& p, const FloatPoint& t1, const FloatPoint& t2, const FloatPoint& t3) +{ + // Compute vectors + FloatSize v0 = t3 - t1; + FloatSize v1 = t2 - t1; + FloatSize v2 = p - t1; + + // Compute dot products + float dot00 = dot(v0, v0); + float dot01 = dot(v0, v1); + float dot02 = dot(v0, v2); + float dot11 = dot(v1, v1); + float dot12 = dot(v1, v2); + + // Compute barycentric coordinates + float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); + float u = (dot11 * dot02 - dot01 * dot12) * invDenom; + float v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + // Check if point is in triangle + return (u >= 0) && (v >= 0) && (u + v <= 1); +} + FloatRect FloatQuad::boundingBox() const { float left = min4(m_p1.x(), m_p2.x(), m_p3.x(), m_p4.x()); @@ -57,4 +85,15 @@ FloatRect FloatQuad::boundingBox() const return FloatRect(left, top, right - left, bottom - top); } +bool FloatQuad::containsPoint(const FloatPoint& p) const +{ + return isPointInTriangle(p, m_p1, m_p2, m_p3) || isPointInTriangle(p, m_p1, m_p3, m_p4); +} + +// Note that we only handle convex quads here. +bool FloatQuad::containsQuad(const FloatQuad& other) const +{ + return containsPoint(other.p1()) && containsPoint(other.p2()) && containsPoint(other.p3()) && containsPoint(other.p4()); +} + } // namespace WebCore diff --git a/WebCore/platform/graphics/FloatQuad.h b/WebCore/platform/graphics/FloatQuad.h index e05b27d..5982967 100644 --- a/WebCore/platform/graphics/FloatQuad.h +++ b/WebCore/platform/graphics/FloatQuad.h @@ -74,6 +74,14 @@ public: // "slanted" empty quads. bool isEmpty() const { return boundingBox().isEmpty(); } + // Tests whether the given point is inside, or on an edge or corner of this quad. + bool containsPoint(const FloatPoint&) const; + + // Tests whether the four corners of other are inside, or coincident with the sides of this quad. + // Note that this only works for convex quads, but that includes all quads that originate + // from transformed rects. + bool containsQuad(const FloatQuad&) const; + FloatRect boundingBox() const; IntRect enclosingBoundingBox() const { diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp index f8bec82..85fe882 100644 --- a/WebCore/platform/graphics/Font.cpp +++ b/WebCore/platform/graphics/Font.cpp @@ -32,6 +32,7 @@ #include "GlyphBuffer.h" #include "WidthIterator.h" #include <wtf/MathExtras.h> +#include <wtf/UnusedParam.h> using namespace WTF; using namespace Unicode; @@ -198,7 +199,7 @@ void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoi return drawComplexText(context, run, point, from, to); } -float Font::floatWidth(const TextRun& run) const +float Font::floatWidth(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const { #if ENABLE(SVG_FONTS) if (primaryFont()->isSVGFont()) @@ -206,16 +207,22 @@ float Font::floatWidth(const TextRun& run) const #endif #if USE(FONT_FAST_PATH) - if (canUseGlyphCache(run)) - return floatWidthForSimpleText(run, 0); + if (canUseGlyphCache(run)) { + // If the complex text implementation cannot return fallback fonts, avoid + // returning them for simple text as well. + static bool returnFallbackFonts = canReturnFallbackFontsForComplexText(); + return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0); + } #endif - return floatWidthForComplexText(run); + return floatWidthForComplexText(run, fallbackFonts); } float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const { -#if ENABLE(SVG_FONTS) +#if !ENABLE(SVG_FONTS) + UNUSED_PARAM(extraCharsAvailable); +#else if (primaryFont()->isSVGFont()) return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName); #endif @@ -275,4 +282,17 @@ FontSelector* Font::fontSelector() const return m_fontList ? m_fontList->fontSelector() : 0; } +static bool shouldUseFontSmoothing = true; + +void Font::setShouldUseSmoothing(bool shouldUseSmoothing) +{ + ASSERT(isMainThread()); + shouldUseFontSmoothing = shouldUseSmoothing; +} + +bool Font::shouldUseSmoothing() +{ + return shouldUseFontSmoothing; +} + } diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h index 1bfee8f..8d85d8b 100644 --- a/WebCore/platform/graphics/Font.h +++ b/WebCore/platform/graphics/Font.h @@ -78,8 +78,8 @@ public: void drawText(GraphicsContext*, const TextRun&, const FloatPoint&, int from = 0, int to = -1) const; - int width(const TextRun& run) const { return lroundf(floatWidth(run)); } - float floatWidth(const TextRun&) const; + int width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts = 0) const { return lroundf(floatWidth(run, fallbackFonts)); } + float floatWidth(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0) const; float floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const; int offsetForPosition(const TextRun&, int position, bool includePartialGlyphs) const; @@ -112,17 +112,19 @@ public: int lineGap() const { return primaryFont()->lineGap(); } float xHeight() const { return primaryFont()->xHeight(); } unsigned unitsPerEm() const { return primaryFont()->unitsPerEm(); } - int spaceWidth() const { return (int)ceilf(primaryFont()->m_adjustedSpaceWidth + m_letterSpacing); } + int spaceWidth() const { return (int)ceilf(primaryFont()->adjustedSpaceWidth() + m_letterSpacing); } int tabWidth() const { return 8 * spaceWidth(); } - const SimpleFontData* primaryFont() const { + const SimpleFontData* primaryFont() const + { + ASSERT(isMainThread()); if (!m_cachedPrimaryFont) cachePrimaryFont(); return m_cachedPrimaryFont; } const FontData* fontDataAt(unsigned) const; - const GlyphData& glyphDataForCharacter(UChar32, bool mirror, bool forceSmallCaps = false) const; + GlyphData glyphDataForCharacter(UChar32, bool mirror, bool forceSmallCaps = false) const; // Used for complex text, and does not utilize the glyph map cache. const FontData* fontDataForCharacters(const UChar*, int length) const; @@ -130,6 +132,9 @@ public: QFont font() const; #endif + static void setShouldUseSmoothing(bool); + static bool shouldUseSmoothing(); + private: #if ENABLE(SVG_FONTS) void drawTextUsingSVGFont(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; @@ -144,13 +149,15 @@ private: void drawSimpleText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; void drawGlyphs(GraphicsContext*, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const; void drawGlyphBuffer(GraphicsContext*, const GlyphBuffer&, const TextRun&, const FloatPoint&) const; - float floatWidthForSimpleText(const TextRun&, GlyphBuffer*) const; + float floatWidthForSimpleText(const TextRun&, GlyphBuffer*, HashSet<const SimpleFontData*>* fallbackFonts = 0) const; int offsetForPositionForSimpleText(const TextRun&, int position, bool includePartialGlyphs) const; FloatRect selectionRectForSimpleText(const TextRun&, const IntPoint&, int h, int from, int to) const; + + static bool canReturnFallbackFontsForComplexText(); #endif void drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; - float floatWidthForComplexText(const TextRun&) const; + float floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0) const; int offsetForPositionForComplexText(const TextRun&, int position, bool includePartialGlyphs) const; FloatRect selectionRectForComplexText(const TextRun&, const IntPoint&, int h, int from, int to) const; void cachePrimaryFont() const; diff --git a/WebCore/platform/graphics/FontCache.cpp b/WebCore/platform/graphics/FontCache.cpp index 130313d..d9b4b28 100644 --- a/WebCore/platform/graphics/FontCache.cpp +++ b/WebCore/platform/graphics/FontCache.cpp @@ -307,12 +307,13 @@ void FontCache::purgeInactiveFontData(int count) isPurging = true; + Vector<const SimpleFontData*, 20> fontDataToDelete; ListHashSet<const SimpleFontData*>::iterator end = gInactiveFontData->end(); ListHashSet<const SimpleFontData*>::iterator it = gInactiveFontData->begin(); for (int i = 0; i < count && it != end; ++it, ++i) { const SimpleFontData* fontData = *it.get(); gFontDataCache->remove(fontData->platformData()); - delete fontData; + fontDataToDelete.append(fontData); } if (it == end) { @@ -323,6 +324,10 @@ void FontCache::purgeInactiveFontData(int count) gInactiveFontData->remove(gInactiveFontData->begin()); } + size_t fontDataToDeleteCount = fontDataToDelete.size(); + for (size_t i = 0; i < fontDataToDeleteCount; ++i) + delete fontDataToDelete[i]; + Vector<FontPlatformDataCacheKey> keysToRemove; keysToRemove.reserveInitialCapacity(gFontPlatformDataCache->size()); FontPlatformDataCache::iterator platformDataEnd = gFontPlatformDataCache->end(); diff --git a/WebCore/platform/graphics/FontCache.h b/WebCore/platform/graphics/FontCache.h index 8820045..3c0f2d9 100644 --- a/WebCore/platform/graphics/FontCache.h +++ b/WebCore/platform/graphics/FontCache.h @@ -85,6 +85,7 @@ public: private: FontCache(); + ~FontCache(); // These methods are implemented by each platform. FontPlatformData* getSimilarFontPlatformData(const Font&); diff --git a/WebCore/platform/graphics/FontDescription.h b/WebCore/platform/graphics/FontDescription.h index d13e86a..c893b8a 100644 --- a/WebCore/platform/graphics/FontDescription.h +++ b/WebCore/platform/graphics/FontDescription.h @@ -81,7 +81,7 @@ public: GenericFamilyType genericFamily() const { return static_cast<GenericFamilyType>(m_genericFamily); } bool usePrinterFont() const { return m_usePrinterFont; } FontRenderingMode renderingMode() const { return static_cast<FontRenderingMode>(m_renderingMode); } - int keywordSize() const { return m_keywordSize; } + unsigned keywordSize() const { return m_keywordSize; } FontTraitsMask traitsMask() const; @@ -95,7 +95,7 @@ public: void setGenericFamily(GenericFamilyType genericFamily) { m_genericFamily = genericFamily; } void setUsePrinterFont(bool p) { m_usePrinterFont = p; } void setRenderingMode(FontRenderingMode mode) { m_renderingMode = mode; } - void setKeywordSize(int s) { m_keywordSize = s; } + void setKeywordSize(unsigned s) { m_keywordSize = s; } private: FontFamily m_familyList; // The list of font families to be used. @@ -114,7 +114,7 @@ private: unsigned m_renderingMode : 1; // Used to switch between CG and GDI text on Windows. - int m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium). If so, + unsigned m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium). If so, // then we can accurately translate across different generic families to adjust for different preference settings // (e.g., 13px monospace vs. 16px everything else). Sizes are 1-8 (like the HTML size values for <font>). }; diff --git a/WebCore/platform/graphics/FontFallbackList.cpp b/WebCore/platform/graphics/FontFallbackList.cpp index 06d52d7..decacc5 100644 --- a/WebCore/platform/graphics/FontFallbackList.cpp +++ b/WebCore/platform/graphics/FontFallbackList.cpp @@ -36,10 +36,10 @@ namespace WebCore { FontFallbackList::FontFallbackList() - : m_familyIndex(0) + : m_fontSelector(0) + , m_familyIndex(0) , m_pitch(UnknownPitch) , m_loadingCustomFonts(false) - , m_fontSelector(0) , m_generation(fontCache()->generation()) { } diff --git a/WebCore/platform/graphics/FontFallbackList.h b/WebCore/platform/graphics/FontFallbackList.h index a23b32c..07938ae 100644 --- a/WebCore/platform/graphics/FontFallbackList.h +++ b/WebCore/platform/graphics/FontFallbackList.h @@ -66,10 +66,10 @@ private: void releaseFontData(); mutable Vector<pair<const FontData*, bool>, 1> m_fontList; + RefPtr<FontSelector> m_fontSelector; mutable int m_familyIndex; mutable Pitch m_pitch; mutable bool m_loadingCustomFonts; - RefPtr<FontSelector> m_fontSelector; unsigned m_generation; friend class Font; diff --git a/WebCore/platform/graphics/FontFastPath.cpp b/WebCore/platform/graphics/FontFastPath.cpp index 635aba9..deac1b6 100644 --- a/WebCore/platform/graphics/FontFastPath.cpp +++ b/WebCore/platform/graphics/FontFastPath.cpp @@ -39,11 +39,13 @@ using namespace Unicode; namespace WebCore { -const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const +GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const { + ASSERT(isMainThread()); + bool useSmallCapsFont = forceSmallCaps; if (m_fontDescription.smallCaps()) { - UChar32 upperC = Unicode::toUpper(c); + UChar32 upperC = toUpper(c); if (upperC != c) { c = upperC; useSmallCapsFont = true; @@ -70,7 +72,7 @@ const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS while (true) { page = node->page(); if (page) { - const GlyphData& data = page->glyphDataForCharacter(c); + GlyphData data = page->glyphDataForCharacter(c); if (data.fontData) return data; if (node->isSystemFallback()) @@ -88,7 +90,7 @@ const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS while (true) { page = node->page(); if (page) { - const GlyphData& data = page->glyphDataForCharacter(c); + GlyphData data = page->glyphDataForCharacter(c); if (data.fontData) { // The smallCapsFontData function should not normally return 0. // But if it does, we will just render the capital letter big. @@ -99,7 +101,7 @@ const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber); const GlyphPage* smallCapsPage = smallCapsNode->page(); if (smallCapsPage) { - const GlyphData& data = smallCapsPage->glyphDataForCharacter(c); + GlyphData data = smallCapsPage->glyphDataForCharacter(c); if (data.fontData) return data; } @@ -150,7 +152,7 @@ const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS if (characterFontData) { // Got the fallback glyph and font. GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page(); - const GlyphData& data = fallbackPage && fallbackPage->glyphDataForCharacter(c).fontData ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); + GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); // Cache it so we don't have to do system fallback again next time. if (!useSmallCapsFont) page->setGlyphDataForCharacter(c, data.glyph, data.fontData); @@ -159,7 +161,7 @@ const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS // Even system fallback can fail; use the missing glyph in that case. // FIXME: It would be nicer to use the missing glyph from the last resort font instead. - const GlyphData& data = primaryFont()->missingGlyphData(); + GlyphData data = primaryFont()->missingGlyphData(); if (!useSmallCapsFont) page->setGlyphDataForCharacter(c, data.glyph, data.fontData); return data; @@ -296,9 +298,9 @@ void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuf drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); } -float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const +float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts) const { - WidthIterator it(this, run); + WidthIterator it(this, run, fallbackFonts); it.advance(run.length(), glyphBuffer); return it.m_runWidthSoFar; } diff --git a/WebCore/platform/graphics/GeneratedImage.cpp b/WebCore/platform/graphics/GeneratedImage.cpp index 15e27d7..c40a40a 100644 --- a/WebCore/platform/graphics/GeneratedImage.cpp +++ b/WebCore/platform/graphics/GeneratedImage.cpp @@ -51,7 +51,7 @@ void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcR const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& destRect) { // Create a BitmapImage and call drawPattern on it. - auto_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(m_size, false); + OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(m_size, false); ASSERT(imageBuffer.get()); // Fill with the gradient. diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/WebCore/platform/graphics/GlyphPageTreeNode.cpp index bd838de..a34a192 100644 --- a/WebCore/platform/graphics/GlyphPageTreeNode.cpp +++ b/WebCore/platform/graphics/GlyphPageTreeNode.cpp @@ -220,8 +220,8 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu if (scratchPage) { ASSERT(to <= static_cast<int>(GlyphPage::size)); for (int j = from; j < to; j++) { - if (!m_page->m_glyphs[j].glyph && pageToFill->m_glyphs[j].glyph) - m_page->m_glyphs[j] = pageToFill->m_glyphs[j]; + if (!m_page->glyphAt(j) && pageToFill->glyphAt(j)) + m_page->setGlyphDataForIndex(j, pageToFill->glyphDataForIndex(j)); } } } @@ -265,15 +265,13 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu // has added anything. bool newGlyphs = false; for (unsigned i = 0; i < GlyphPage::size; i++) { - if (parentPage->m_glyphs[i].glyph) - m_page->m_glyphs[i] = parentPage->m_glyphs[i]; - else if (fallbackPage->m_glyphs[i].glyph) { - m_page->m_glyphs[i] = fallbackPage->m_glyphs[i]; + if (parentPage->glyphAt(i)) + m_page->setGlyphDataForIndex(i, parentPage->glyphDataForIndex(i)); + else if (fallbackPage->glyphAt(i)) { + m_page->setGlyphDataForIndex(i, fallbackPage->glyphDataForIndex(i)); newGlyphs = true; - } else { - const GlyphData data = { 0, 0 }; - m_page->m_glyphs[i] = data; - } + } else + m_page->setGlyphDataForIndex(i, 0, 0); } if (!newGlyphs) @@ -288,12 +286,9 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu // ever finds it needs a glyph out of the system fallback page, it will // ask the system for the best font to use and fill that glyph in for us. if (parentPage) - memcpy(m_page->m_glyphs, parentPage->m_glyphs, GlyphPage::size * sizeof(m_page->m_glyphs[0])); - else { - const GlyphData data = { 0, 0 }; - for (unsigned i = 0; i < GlyphPage::size; i++) - m_page->m_glyphs[i] = data; - } + m_page->copyFrom(*parentPage); + else + m_page->clear(); } } diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.h b/WebCore/platform/graphics/GlyphPageTreeNode.h index 240b492..80e87aa 100644 --- a/WebCore/platform/graphics/GlyphPageTreeNode.h +++ b/WebCore/platform/graphics/GlyphPageTreeNode.h @@ -29,6 +29,7 @@ #ifndef GlyphPageTreeNode_h #define GlyphPageTreeNode_h +#include <string.h> #include <wtf/HashMap.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -45,6 +46,11 @@ typedef unsigned short Glyph; // Holds the glyph index and the corresponding SimpleFontData information for a given // character. struct GlyphData { + GlyphData(Glyph g = 0, const SimpleFontData* f = 0) + : glyph(g) + , fontData(f) + { + } Glyph glyph; const SimpleFontData* fontData; }; @@ -54,30 +60,69 @@ struct GlyphData { // starting from 0 and incrementing for each 256 glyphs. // // One page may actually include glyphs from other fonts if the characters are -// missing in the parimary font. It is owned by exactly one GlyphPageTreeNode, +// missing in the primary font. It is owned by exactly one GlyphPageTreeNode, // although multiple nodes may reference it as their "page" if they are supposed // to be overriding the parent's node, but provide no additional information. -struct GlyphPage : public RefCounted<GlyphPage> { +class GlyphPage : public RefCounted<GlyphPage> { +public: static PassRefPtr<GlyphPage> create(GlyphPageTreeNode* owner) { return adoptRef(new GlyphPage(owner)); } static const size_t size = 256; // Covers Latin-1 in a single page. - GlyphData m_glyphs[size]; - GlyphPageTreeNode* m_owner; - const GlyphData& glyphDataForCharacter(UChar32 c) const { return m_glyphs[c % size]; } + unsigned indexForCharacter(UChar32 c) const { return c % size; } + GlyphData glyphDataForCharacter(UChar32 c) const + { + unsigned index = indexForCharacter(c); + return GlyphData(m_glyphs[index], m_glyphFontData[index]); + } + + GlyphData glyphDataForIndex(unsigned index) const + { + ASSERT(index < size); + return GlyphData(m_glyphs[index], m_glyphFontData[index]); + } + + Glyph glyphAt(unsigned index) const + { + ASSERT(index < size); + return m_glyphs[index]; + } + + const SimpleFontData* fontDataForCharacter(UChar32 c) const + { + return m_glyphFontData[indexForCharacter(c)]; + } + void setGlyphDataForCharacter(UChar32 c, Glyph g, const SimpleFontData* f) { - setGlyphDataForIndex(c % size, g, f); + setGlyphDataForIndex(indexForCharacter(c), g, f); } void setGlyphDataForIndex(unsigned index, Glyph g, const SimpleFontData* f) { ASSERT(index < size); - m_glyphs[index].glyph = g; - m_glyphs[index].fontData = f; + m_glyphs[index] = g; + m_glyphFontData[index] = f; + } + void setGlyphDataForIndex(unsigned index, const GlyphData& glyphData) + { + setGlyphDataForIndex(index, glyphData.glyph, glyphData.fontData); + } + + void copyFrom(const GlyphPage& other) + { + memcpy(m_glyphs, other.m_glyphs, sizeof(m_glyphs)); + memcpy(m_glyphFontData, other.m_glyphFontData, sizeof(m_glyphFontData)); + } + + void clear() + { + memset(m_glyphs, 0, sizeof(m_glyphs)); + memset(m_glyphFontData, 0, sizeof(m_glyphFontData)); } + GlyphPageTreeNode* owner() const { return m_owner; } // Implemented by the platform. @@ -88,6 +133,12 @@ private: : m_owner(owner) { } + + // Separate arrays, rather than array of GlyphData, to save space. + Glyph m_glyphs[size]; + const SimpleFontData* m_glyphFontData[size]; + + GlyphPageTreeNode* m_owner; }; // The glyph page tree is a data structure that maps (FontData, glyph page number) diff --git a/WebCore/platform/graphics/Gradient.cpp b/WebCore/platform/graphics/Gradient.cpp index 24e8bbf..51c7162 100644 --- a/WebCore/platform/graphics/Gradient.cpp +++ b/WebCore/platform/graphics/Gradient.cpp @@ -52,6 +52,7 @@ Gradient::Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r , m_r1(r1) , m_stopsSorted(false) , m_lastStop(0) + , m_spreadMethod(SpreadMethodPad) { platformInit(); } diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp index 8cad794..4dae3d2 100644 --- a/WebCore/platform/graphics/GraphicsContext.cpp +++ b/WebCore/platform/graphics/GraphicsContext.cpp @@ -30,7 +30,6 @@ #include "Generator.h" #include "GraphicsContextPrivate.h" #include "Font.h" -#include "NotImplemented.h" using namespace std; @@ -337,7 +336,7 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const F BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft; - bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, new BidiContext(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride()))); + bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, BidiContext::create(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride()))); bidiResolver.setPosition(TextRunIterator(&run, 0)); bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length())); diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index 7c1c4b0..3fdafad 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -374,6 +374,7 @@ namespace WebCore { #if PLATFORM(QT) && defined(Q_WS_WIN) HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); + bool shouldIncludeChildWindows() const { return false; } #endif #if PLATFORM(QT) diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index f928ce8..ae51951 100644 --- a/WebCore/platform/graphics/GraphicsLayer.h +++ b/WebCore/platform/graphics/GraphicsLayer.h @@ -288,8 +288,10 @@ public: int incrementRepaintCount() { return ++m_repaintCount; } #endif - // Platform behaviors - static bool graphicsContextsFlipped(); + // Report whether the underlying compositing system uses a top-down + // or a bottom-up coordinate system. + enum CompositingCoordinatesOrientation { CompositingCoordinatesTopDown, CompositingCoordinatesBottomUp }; + static CompositingCoordinatesOrientation compositingCoordinatesOrientation(); #ifndef NDEBUG static bool showDebugBorders(); diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h index 70f6d49..cff8b22 100644 --- a/WebCore/platform/graphics/Image.h +++ b/WebCore/platform/graphics/Image.h @@ -61,8 +61,8 @@ class NativeImageSkia; #include <QPixmap> #endif -#if PLATFORM(SGL) -class SkBitmapRef; +#if PLATFORM(GTK) +typedef struct _GdkPixbuf GdkPixbuf; #endif namespace WebCore { @@ -147,10 +147,13 @@ public: #endif #if PLATFORM(SGL) - virtual SkBitmapRef* getBitmap() { return 0; } virtual void setURL(const String& str) {} #endif +#if PLATFORM(GTK) + virtual GdkPixbuf* getGdkPixbuf() { return 0; } +#endif + protected: Image(ImageObserver* = 0); diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h index 14f7461..573e274 100644 --- a/WebCore/platform/graphics/ImageBuffer.h +++ b/WebCore/platform/graphics/ImageBuffer.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,8 +32,8 @@ #include "IntSize.h" #include "ImageBufferData.h" #include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> #include <wtf/PassRefPtr.h> -#include <memory> namespace WebCore { @@ -46,13 +46,13 @@ namespace WebCore { class ImageBuffer : Noncopyable { public: // Will return a null pointer on allocation failure. - static std::auto_ptr<ImageBuffer> create(const IntSize& size, bool grayScale) + static PassOwnPtr<ImageBuffer> create(const IntSize& size, bool grayScale) { bool success = false; - std::auto_ptr<ImageBuffer> buf(new ImageBuffer(size, grayScale, success)); + OwnPtr<ImageBuffer> buf(new ImageBuffer(size, grayScale, success)); if (success) - return buf; - return std::auto_ptr<ImageBuffer>(); + return buf.release(); + return 0; } ~ImageBuffer(); @@ -80,7 +80,7 @@ namespace WebCore { OwnPtr<GraphicsContext> m_context; mutable RefPtr<Image> m_image; - // This constructor will place its succes into the given out-variable + // This constructor will place its success into the given out-variable // so that create() knows when it should return failure. ImageBuffer(const IntSize&, bool grayScale, bool& success); }; diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h index 07cc2c2..d4a1658 100644 --- a/WebCore/platform/graphics/ImageSource.h +++ b/WebCore/platform/graphics/ImageSource.h @@ -31,6 +31,7 @@ #if PLATFORM(WX) class wxBitmap; +class wxGraphicsBitmap; #elif PLATFORM(CG) typedef struct CGImageSource* CGImageSourceRef; typedef struct CGImage* CGImageRef; @@ -61,7 +62,11 @@ class String; class ImageDecoder; typedef ImageDecoder* NativeImageSourcePtr; typedef const Vector<char>* NativeBytePtr; +#if USE(WXGC) +typedef wxGraphicsBitmap* NativeImagePtr; +#else typedef wxBitmap* NativeImagePtr; +#endif #elif PLATFORM(CG) typedef CGImageSourceRef NativeImageSourcePtr; typedef CGImageRef NativeImagePtr; diff --git a/WebCore/platform/graphics/IntPoint.h b/WebCore/platform/graphics/IntPoint.h index a05b1f0..1bfeeaa 100644 --- a/WebCore/platform/graphics/IntPoint.h +++ b/WebCore/platform/graphics/IntPoint.h @@ -70,6 +70,7 @@ class IntPoint { public: IntPoint() : m_x(0), m_y(0) { } IntPoint(int x, int y) : m_x(x), m_y(y) { } + explicit IntPoint(const IntSize& size) : m_x(size.width()), m_y(size.height()) { } int x() const { return m_x; } int y() const { return m_y; } diff --git a/WebCore/platform/graphics/IntSize.h b/WebCore/platform/graphics/IntSize.h index 4d36545..cac0bd1 100644 --- a/WebCore/platform/graphics/IntSize.h +++ b/WebCore/platform/graphics/IntSize.h @@ -73,6 +73,12 @@ public: m_height += height; } + void scale(float scale) + { + m_width = static_cast<int>(static_cast<float>(m_width) * scale); + m_height = static_cast<int>(static_cast<float>(m_height) * scale); + } + IntSize expandedTo(const IntSize& other) const { return IntSize(m_width > other.m_width ? m_width : other.m_width, diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index 99d6aa4..b580474 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -183,6 +183,7 @@ MediaPlayer::MediaPlayer(MediaPlayerClient* client) , m_visible(false) , m_rate(1.0f) , m_volume(1.0f) + , m_autobuffer(false) #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) , m_playerProxy(0) #endif @@ -206,11 +207,20 @@ void MediaPlayer::load(const String& url, const ContentType& contentType) String type = contentType.type(); String codecs = contentType.parameter("codecs"); - // if we don't know the MIME type, see if the path can help - if (type.isEmpty()) - type = MIMETypeRegistry::getMIMETypeForPath(url); + // if we don't know the MIME type, see if the extension can help + if (type.isEmpty() || type == "application/octet-stream" || type == "text/plain") { + int pos = url.reverseFind('.'); + if (pos >= 0) { + String extension = url.substring(pos + 1); + String mediaType = MIMETypeRegistry::getMediaMIMETypeForExtension(extension); + if (!mediaType.isEmpty()) + type = mediaType; + } + } - MediaPlayerFactory* engine = chooseBestEngineForTypeAndCodecs(type, codecs); + MediaPlayerFactory* engine = 0; + if (!type.isEmpty()) + engine = chooseBestEngineForTypeAndCodecs(type, codecs); // if we didn't find an engine that claims the MIME type, just use the first engine if (!engine) @@ -260,6 +270,11 @@ float MediaPlayer::duration() const return m_private->duration(); } +float MediaPlayer::startTime() const +{ + return m_private->startTime(); +} + float MediaPlayer::currentTime() const { return m_private->currentTime(); @@ -382,6 +397,19 @@ void MediaPlayer::setVisible(bool b) m_private->setVisible(b); } +bool MediaPlayer::autobuffer() const +{ + return m_autobuffer; +} + +void MediaPlayer::setAutobuffer(bool b) +{ + if (m_autobuffer != b) { + m_autobuffer = b; + m_private->setAutobuffer(b); + } +} + void MediaPlayer::paint(GraphicsContext* p, const IntRect& r) { m_private->paint(p, r); diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h index 7d90e44..9b2f685 100644 --- a/WebCore/platform/graphics/MediaPlayer.h +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -76,6 +76,11 @@ public: // the movie size has changed virtual void mediaPlayerSizeChanged(MediaPlayer*) { } + + // The MediaPlayer has found potentially problematic media content. + // This is used internally to trigger swapping from a <video> + // element to an <embed> in standalone documents + virtual void mediaPlayerSawUnsupportedTracks(MediaPlayer*) { } }; class MediaPlayer : Noncopyable { @@ -88,7 +93,7 @@ public: static MediaPlayer::SupportsType supportsType(ContentType contentType); static void getSupportedTypes(HashSet<String>&); static bool isAvailable(); - + IntSize naturalSize(); bool hasVideo(); @@ -114,6 +119,8 @@ public: float duration() const; float currentTime() const; void seek(float time); + + float startTime() const; void setEndTime(float time); @@ -131,7 +138,10 @@ public: void setVolume(float); int dataRate() const; - + + bool autobuffer() const; + void setAutobuffer(bool); + void paint(GraphicsContext*, const IntRect&); enum NetworkState { Empty, Idle, Loading, Loaded, FormatError, NetworkError, DecodeError }; @@ -169,6 +179,7 @@ private: bool m_visible; float m_rate; float m_volume; + bool m_autobuffer; #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) WebMediaPlayerProxy* m_playerProxy; // not owned or used, passed to m_private #endif diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h index 2e73e7e..e17259c 100644 --- a/WebCore/platform/graphics/MediaPlayerPrivate.h +++ b/WebCore/platform/graphics/MediaPlayerPrivate.h @@ -58,7 +58,9 @@ public: virtual void seek(float time) = 0; virtual bool seeking() const = 0; - virtual void setEndTime(float time) = 0; + virtual float startTime() const { return 0; } + + virtual void setEndTime(float) = 0; virtual void setRate(float) = 0; virtual bool paused() const = 0; @@ -81,6 +83,8 @@ public: virtual void paint(GraphicsContext*, const IntRect&) = 0 ; + virtual void setAutobuffer(bool) { }; + #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) virtual void setPoster(const String& url) = 0; virtual void deliverNotification(MediaPlayerProxyNotificationType) = 0; diff --git a/WebCore/platform/graphics/Path.cpp b/WebCore/platform/graphics/Path.cpp index f3450be..e30703c 100644 --- a/WebCore/platform/graphics/Path.cpp +++ b/WebCore/platform/graphics/Path.cpp @@ -35,7 +35,7 @@ #include <math.h> #include <wtf/MathExtras.h> -const float QUARTER = 0.552f; // approximation of control point positions on a bezier +static const float QUARTER = 0.552f; // approximation of control point positions on a bezier // to simulate a quarter of a circle. namespace WebCore { diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp index 9f51037..bab7d99 100644 --- a/WebCore/platform/graphics/SimpleFontData.cpp +++ b/WebCore/platform/graphics/SimpleFontData.cpp @@ -32,18 +32,24 @@ #include "Font.h" #include "FontCache.h" + #if ENABLE(SVG_FONTS) #include "SVGFontData.h" +#include "SVGFontElement.h" #include "SVGFontFaceElement.h" +#include "SVGGlyphElement.h" #endif #include <wtf/MathExtras.h> +#include <wtf/UnusedParam.h> + +using namespace std; namespace WebCore { SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData) : m_unitsPerEm(defaultUnitsPerEm) - , m_font(f) + , m_platformData(f) , m_treatAsFixedPitch(false) #if ENABLE(SVG_FONTS) , m_svgFontData(svgFontData) @@ -52,24 +58,40 @@ SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool , m_isLoading(loading) , m_smallCapsFontData(0) { -#if ENABLE(SVG_FONTS) +#if !ENABLE(SVG_FONTS) + UNUSED_PARAM(svgFontData); +#else if (SVGFontFaceElement* svgFontFaceElement = svgFontData ? svgFontData->svgFontFaceElement() : 0) { - m_unitsPerEm = svgFontFaceElement->unitsPerEm(); + m_unitsPerEm = svgFontFaceElement->unitsPerEm(); - double scale = f.size(); - if (m_unitsPerEm) - scale /= m_unitsPerEm; + double scale = f.size(); + if (m_unitsPerEm) + scale /= m_unitsPerEm; m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale); m_descent = static_cast<int>(svgFontFaceElement->descent() * scale); m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale); m_lineGap = 0.1f * f.size(); m_lineSpacing = m_ascent + m_descent + m_lineGap; - + + SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); + + Vector<SVGGlyphIdentifier> spaceGlyphs; + associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs); + m_spaceWidth = spaceGlyphs.isEmpty() ? m_xHeight : static_cast<float>(spaceGlyphs.first().horizontalAdvanceX * scale); + + Vector<SVGGlyphIdentifier> numeralZeroGlyphs; + associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs); + m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : static_cast<float>(numeralZeroGlyphs.first().horizontalAdvanceX * scale); + + Vector<SVGGlyphIdentifier> letterWGlyphs; + associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs); + m_maxCharWidth = letterWGlyphs.isEmpty() ? m_ascent : static_cast<float>(letterWGlyphs.first().horizontalAdvanceX * scale); + + // FIXME: is there a way we can get the space glyph from the SVGGlyphIdentifier above? m_spaceGlyph = 0; - m_spaceWidth = 0; - m_adjustedSpaceWidth = 0; determinePitch(); + m_adjustedSpaceWidth = roundf(m_spaceWidth); m_missingGlyphData.fontData = this; m_missingGlyphData.glyph = 0; return; @@ -78,9 +100,31 @@ SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool platformInit(); platformGlyphInit(); + platformCharWidthInit(); } #if !PLATFORM(QT) +// Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font. +void SimpleFontData::initCharWidths() +{ + GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); + + // Treat the width of a '0' as the avgCharWidth. + if (m_avgCharWidth <= 0.f && glyphPageZero) { + static const UChar32 digitZeroChar = '0'; + Glyph digitZeroGlyph = glyphPageZero->glyphDataForCharacter(digitZeroChar).glyph; + if (digitZeroGlyph) + m_avgCharWidth = widthForGlyph(digitZeroGlyph); + } + + // If we can't retrieve the width of a '0', fall back to the x height. + if (m_avgCharWidth <= 0.f) + m_avgCharWidth = m_xHeight; + + if (m_maxCharWidth <= 0.f) + m_maxCharWidth = max<float>(m_avgCharWidth, m_ascent); +} + void SimpleFontData::platformGlyphInit() { GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h index d2dd0b9..aab6429 100644 --- a/WebCore/platform/graphics/SimpleFontData.h +++ b/WebCore/platform/graphics/SimpleFontData.h @@ -61,7 +61,7 @@ public: virtual ~SimpleFontData(); public: - const FontPlatformData& platformData() const { return m_font; } + const FontPlatformData& platformData() const { return m_platformData; } SimpleFontData* smallCapsFontData(const FontDescription& fontDescription) const; // vertical metrics @@ -69,12 +69,23 @@ public: int descent() const { return m_descent; } int lineSpacing() const { return m_lineSpacing; } int lineGap() const { return m_lineGap; } + float maxCharWidth() const { return m_maxCharWidth; } + float avgCharWidth() const { return m_avgCharWidth; } float xHeight() const { return m_xHeight; } unsigned unitsPerEm() const { return m_unitsPerEm; } float widthForGlyph(Glyph) const; float platformWidthForGlyph(Glyph) const; + float spaceWidth() const { return m_spaceWidth; } + float adjustedSpaceWidth() const { return m_adjustedSpaceWidth; } + +#if PLATFORM(CG) || PLATFORM(CAIRO) + float syntheticBoldOffset() const { return m_syntheticBoldOffset; } +#endif + + Glyph spaceGlyph() const { return m_spaceGlyph; } + virtual const SimpleFontData* fontDataForCharacter(UChar32) const; virtual bool containsCharacters(const UChar*, int length) const; @@ -95,7 +106,7 @@ public: const GlyphData& missingGlyphData() const { return m_missingGlyphData; } #if PLATFORM(MAC) - NSFont* getNSFont() const { return m_font.font(); } + NSFont* getNSFont() const { return m_platformData.font(); } #endif #if USE(CORE_TEXT) @@ -114,7 +125,7 @@ public: #endif #if PLATFORM(QT) - QFont getQtFont() const { return m_font.font(); } + QFont getQtFont() const { return m_platformData.font(); } #endif #if PLATFORM(WIN) @@ -131,14 +142,17 @@ public: #endif #if PLATFORM(WX) - wxFont* getWxFont() const { return m_font.font(); } + wxFont* getWxFont() const { return m_platformData.font(); } #endif private: void platformInit(); void platformGlyphInit(); + void platformCharWidthInit(); void platformDestroy(); + void initCharWidths(); + void commonInit(); #if PLATFORM(WIN) @@ -147,15 +161,16 @@ private: float widthForGDIGlyph(Glyph glyph) const; #endif -public: int m_ascent; int m_descent; int m_lineSpacing; int m_lineGap; + float m_maxCharWidth; + float m_avgCharWidth; float m_xHeight; unsigned m_unitsPerEm; - FontPlatformData m_font; + FontPlatformData m_platformData; mutable GlyphWidthMap m_glyphToWidthMap; @@ -176,22 +191,26 @@ public: mutable SimpleFontData* m_smallCapsFontData; -#if PLATFORM(CG) || PLATFORM(WIN) +#if PLATFORM(CG) || PLATFORM(CAIRO) float m_syntheticBoldOffset; #endif -#if PLATFORM(MAC) #ifdef BUILDING_ON_TIGER +public: void* m_styleGroup; -#endif + +private: #endif #if USE(ATSUI) +public: mutable ATSUStyle m_ATSUStyle; mutable bool m_ATSUStyleInitialized; mutable bool m_ATSUMirrors; mutable bool m_checkedShapesArabic; mutable bool m_shapesArabic; + +private: #endif #if USE(CORE_TEXT) diff --git a/WebCore/platform/graphics/WidthIterator.cpp b/WebCore/platform/graphics/WidthIterator.cpp index a16d739..9157310 100644 --- a/WebCore/platform/graphics/WidthIterator.cpp +++ b/WebCore/platform/graphics/WidthIterator.cpp @@ -39,13 +39,14 @@ namespace WebCore { // According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values static const uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8; -WidthIterator::WidthIterator(const Font* font, const TextRun& run) +WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) : m_font(font) , m_run(run) , m_end(run.length()) , m_currentCharacter(0) , m_runWidthSoFar(0) , m_finalRoundingWidth(0) + , m_fallbackFonts(fallbackFonts) { // If the padding is non-zero, count the number of spaces in the run // and divide that by the padding for per space addition. @@ -78,7 +79,10 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) float runWidthSoFar = m_runWidthSoFar; float lastRoundingWidth = m_finalRoundingWidth; - + + const SimpleFontData* primaryFont = m_font->primaryFont(); + const SimpleFontData* lastFontData = primaryFont; + while (currentCharacter < offset) { UChar32 c = *cp; unsigned clusterLength = 1; @@ -126,16 +130,29 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) // First, we round spaces to an adjusted width in all fonts. // Second, in fixed-pitch fonts we ensure that all characters that // match the width of the space character have the same width as the space character. - if (width == fontData->m_spaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding()) { - width = fontData->m_adjustedSpaceWidth; + if (width == fontData->spaceWidth() && (fontData->pitch() == FixedPitch || glyph == fontData->spaceGlyph()) && m_run.applyWordRounding()) + width = fontData->adjustedSpaceWidth(); + } + + if (fontData != lastFontData && width) { + lastFontData = fontData; + if (m_fallbackFonts && fontData != primaryFont) { + // FIXME: This does a little extra work that could be avoided if + // glyphDataForCharacter() returned whether it chose to use a small caps font. + if (!m_font->isSmallCaps() || c == toUpper(c)) + m_fallbackFonts->add(fontData); + else { + const GlyphData& uppercaseGlyphData = m_font->glyphDataForCharacter(toUpper(c), rtl); + if (uppercaseGlyphData.fontData != primaryFont) + m_fallbackFonts->add(uppercaseGlyphData.fontData); + } } } if (hasExtraSpacing) { // Account for letter-spacing. - if (width && m_font->letterSpacing()) { + if (width && m_font->letterSpacing()) width += m_font->letterSpacing(); - } if (Font::treatAsSpace(c)) { // Account for padding. WebCore uses space padding to justify text. @@ -153,9 +170,8 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) // Account for word spacing. // We apply additional space between "words" by adding width to the space character. - if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing()) { + if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing()) width += m_font->wordSpacing(); - } } } @@ -172,9 +188,8 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) // Force characters that are used to determine word boundaries for the rounding hack // to be integer width, so following words will start on an integer boundary. - if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) { + if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) width = ceilf(width); - } // Check to see if the next character is a "rounding hack character", if so, adjust // width so that the total run width will be on an integer boundary. diff --git a/WebCore/platform/graphics/WidthIterator.h b/WebCore/platform/graphics/WidthIterator.h index 5706d1e..7ca4198 100644 --- a/WebCore/platform/graphics/WidthIterator.h +++ b/WebCore/platform/graphics/WidthIterator.h @@ -22,16 +22,18 @@ #ifndef WidthIterator_h #define WidthIterator_h +#include <wtf/HashSet.h> #include <wtf/unicode/Unicode.h> namespace WebCore { class Font; class GlyphBuffer; +class SimpleFontData; class TextRun; struct WidthIterator { - WidthIterator(const Font*, const TextRun&); + WidthIterator(const Font*, const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0); void advance(int to, GlyphBuffer* = 0); bool advanceOneCharacter(float& width, GlyphBuffer* = 0); @@ -49,6 +51,7 @@ struct WidthIterator { private: UChar32 normalizeVoicingMarks(int currentCharacter); + HashSet<const SimpleFontData*>* m_fallbackFonts; }; } diff --git a/WebCore/platform/graphics/android/FontAndroid.cpp b/WebCore/platform/graphics/android/FontAndroid.cpp index ca2fca1..a430b07 100644 --- a/WebCore/platform/graphics/android/FontAndroid.cpp +++ b/WebCore/platform/graphics/android/FontAndroid.cpp @@ -107,6 +107,11 @@ static bool setupForText(SkPaint* paint, GraphicsContext* gc, return true; } +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const @@ -206,7 +211,7 @@ void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, paint); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const { SkPaint paint; diff --git a/WebCore/platform/graphics/android/FontDataAndroid.cpp b/WebCore/platform/graphics/android/FontDataAndroid.cpp index 3d31eaf..2bb53e4 100644 --- a/WebCore/platform/graphics/android/FontDataAndroid.cpp +++ b/WebCore/platform/graphics/android/FontDataAndroid.cpp @@ -48,7 +48,7 @@ void SimpleFontData::platformInit() SkPaint paint; SkPaint::FontMetrics metrics; - m_font.setupPaint(&paint); + m_platformData.setupPaint(&paint); (void)paint.getFontMetrics(&metrics); // use ceil instead of round to favor descent, given a lot of accidental @@ -64,6 +64,13 @@ void SimpleFontData::platformInit() m_lineGap = SkScalarRound(metrics.fLeading); } +void SimpleFontData::platformCharWidthInit() +{ + m_avgCharWidth = 0.f; + m_maxCharWidth = 0.f; + initCharWidths(); +} + void SimpleFontData::platformDestroy() { delete m_smallCapsFontData; @@ -72,7 +79,7 @@ void SimpleFontData::platformDestroy() SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { if (!m_smallCapsFontData) { - m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_font, fontDescription.computedSize() * 0.7f)); + m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_platformData, fontDescription.computedSize() * 0.7f)); } return m_smallCapsFontData; } @@ -84,7 +91,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con SkPaint paint; uint16_t glyphs[kMaxBufferCount]; - m_font.setupPaint(&paint); + m_platformData.setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); while (length > 0) { @@ -114,7 +121,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const SkPaint paint; - m_font.setupPaint(&paint); + m_platformData.setupPaint(&paint); if (EmojiFont::IsEmojiGlyph(glyph)) return EmojiFont::GetAdvanceWidth(glyph, paint); diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp index b23182d..0f7ae79 100644 --- a/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -36,6 +36,8 @@ #include "SimpleFontData.h" #include "TransformationMatrix.h" +#define SYNTHETIC_OBLIQUE_ANGLE 14 + namespace WebCore { void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, @@ -48,15 +50,23 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from); - float offset = point.x(); + float offset = 0.0f; for (int i = 0; i < numGlyphs; i++) { glyphs[i].x = offset; - glyphs[i].y = point.y(); + glyphs[i].y = 0.0f; offset += glyphBuffer.advanceAt(from + i); } Color fillColor = context->fillColor(); + // Synthetic Oblique + if(font->platformData().syntheticOblique()) { + cairo_matrix_t mat = {1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, point.x(), point.y()}; + cairo_transform(cr, &mat); + } else { + cairo_translate(cr, point.x(), point.y()); + } + // Text shadow, inspired by FontMac IntSize shadowSize; int shadowBlur = 0; @@ -77,6 +87,12 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_translate(cr, shadowSize.width(), shadowSize.height()); cairo_show_glyphs(cr, glyphs, numGlyphs); + if (font->syntheticBoldOffset()) { + cairo_save(cr); + cairo_translate(cr, font->syntheticBoldOffset(), 0); + cairo_show_glyphs(cr, glyphs, numGlyphs); + cairo_restore(cr); + } cairo_restore(cr); } @@ -103,6 +119,12 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha()); } cairo_show_glyphs(cr, glyphs, numGlyphs); + if (font->syntheticBoldOffset()) { + cairo_save(cr); + cairo_translate(cr, font->syntheticBoldOffset(), 0); + cairo_show_glyphs(cr, glyphs, numGlyphs); + cairo_restore(cr); + } } if (context->textDrawingMode() & cTextStroke) { diff --git a/WebCore/platform/graphics/cairo/GradientCairo.cpp b/WebCore/platform/graphics/cairo/GradientCairo.cpp index 72fb0c5..0aada55 100644 --- a/WebCore/platform/graphics/cairo/GradientCairo.cpp +++ b/WebCore/platform/graphics/cairo/GradientCairo.cpp @@ -80,11 +80,11 @@ void Gradient::fill(GraphicsContext* context, const FloatRect& rect) { cairo_t* cr = context->platformContext(); - cairo_save(cr); + context->save(); cairo_set_source(cr, platformGradient()); cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); cairo_fill(cr); - cairo_restore(cr); + context->restore(); } } //namespace diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 35ebd3c..23f30f3 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -92,6 +92,7 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* cr) , m_data(new GraphicsContextPlatformPrivate) { m_data->cr = cairo_reference(cr); + m_data->syncContext(cr); setPaintingDisabled(!cr); } diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h index 55b2e25..531ebf4 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h +++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h @@ -73,6 +73,7 @@ public: void concatCTM(const TransformationMatrix&); void beginTransparencyLayer() { m_transparencyCount++; } void endTransparencyLayer() { m_transparencyCount--; } + void syncContext(PlatformGraphicsContext* cr); #else // On everything else, we do nothing. void save() {} @@ -85,6 +86,7 @@ public: void concatCTM(const TransformationMatrix&) {} void beginTransparencyLayer() {} void endTransparencyLayer() {} + void syncContext(PlatformGraphicsContext* cr) {} #endif cairo_t* cr; diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index dff39b7..d2652d6 100644 --- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -34,7 +34,6 @@ #include "GraphicsContext.h" #include "ImageData.h" #include "MIMETypeRegistry.h" -#include "NotImplemented.h" #include "Pattern.h" #include "PlatformString.h" diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp index 224154e..7c34e6f 100644 --- a/WebCore/platform/graphics/cairo/ImageCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -33,10 +33,12 @@ #include "Color.h" #include "FloatRect.h" #include "GraphicsContext.h" +#include "ImageBuffer.h" #include "ImageObserver.h" #include "TransformationMatrix.h" #include <cairo.h> #include <math.h> +#include <wtf/OwnPtr.h> namespace WebCore { @@ -89,15 +91,19 @@ BitmapImage::BitmapImage(cairo_surface_t* surface, ImageObserver* observer) void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, CompositeOperator op) { + FloatRect srcRect(src); + FloatRect dstRect(dst); + + if (dstRect.width() == 0.0f || dstRect.height() == 0.0f || + srcRect.width() == 0.0f || srcRect.height() == 0.0f) + return; + startAnimation(); cairo_surface_t* image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; - FloatRect srcRect(src); - FloatRect dstRect(dst); - if (mayFillWithSolidColor()) { fillWithSolidColor(context, dstRect, solidColor(), op); return; @@ -106,7 +112,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo IntSize selfSize = size(); cairo_t* cr = context->platformContext(); - cairo_save(cr); + context->save(); // Set the compositing operation. if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) @@ -138,7 +144,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo cairo_clip(cr); cairo_paint_with_alpha(cr, context->getAlpha()); - cairo_restore(cr); + context->restore(); if (imageObserver()) imageObserver()->didDraw(this); @@ -154,7 +160,18 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, con cairo_t* cr = context->platformContext(); context->save(); - // TODO: Make use of tileRect. + IntRect imageSize = enclosingIntRect(tileRect); + OwnPtr<ImageBuffer> imageSurface = ImageBuffer::create(imageSize.size(), false); + + if (!imageSurface) + return; + + if (tileRect.size() != size()) { + cairo_t* clippedImageContext = imageSurface->context()->platformContext(); + cairo_set_source_surface(clippedImageContext, image, -tileRect.x(), -tileRect.y()); + cairo_paint(clippedImageContext); + image = imageSurface->image()->nativeImageForCurrentFrame(); + } cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); @@ -163,7 +180,7 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, con cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST); cairo_matrix_t pattern_matrix = cairo_matrix_t(patternTransform); - cairo_matrix_t phase_matrix = {1, 0, 0, 1, phase.x(), phase.y()}; + cairo_matrix_t phase_matrix = {1, 0, 0, 1, phase.x() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d()}; cairo_matrix_t combined; cairo_matrix_multiply(&combined, &pattern_matrix, &phase_matrix); cairo_matrix_invert(&combined); diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp index c6d54f2..b51caf6 100644 --- a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp @@ -190,13 +190,13 @@ NativeImagePtr ImageSource::createFrameAtIndex(size_t index) // Cairo does not like zero height images. // If we have a zero height image, just pretend we don't have enough data yet. - if (!buffer->height()) + if (!size().height()) return 0; return cairo_image_surface_create_for_data((unsigned char*)buffer->bytes().data(), CAIRO_FORMAT_ARGB32, size().width(), - buffer->height(), + size().height(), size().width()*4); } diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp index 24354d2..13ca1e2 100644 --- a/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -29,7 +29,6 @@ #include "CairoPath.h" #include "FloatRect.h" #include "GraphicsContext.h" -#include "NotImplemented.h" #include "PlatformString.h" #include "StrokeStyleApplier.h" diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index 4b8a555..ab8eb3c 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -116,10 +116,9 @@ void GraphicsContext::drawRect(const IntRect& rect) CGContextRef context = platformContext(); - if (fillColor().alpha()) - CGContextFillRect(context, rect); + CGContextFillRect(context, rect); - if (strokeStyle() != NoStroke && strokeColor().alpha()) { + if (strokeStyle() != NoStroke) { // We do a fill of four rects to simulate the stroke of a border. Color oldFillColor = fillColor(); if (oldFillColor != strokeColor()) @@ -142,7 +141,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (paintingDisabled()) return; - if (strokeStyle() == NoStroke || !strokeColor().alpha()) + if (strokeStyle() == NoStroke) return; float width = strokeThickness(); @@ -277,7 +276,7 @@ void GraphicsContext::drawEllipse(const IntRect& rect) void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) { - if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha()) + if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f) return; CGContextRef context = platformContext(); @@ -366,7 +365,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool antialiased) { - if (paintingDisabled() || !fillColor().alpha() && (strokeThickness() <= 0 || strokeStyle() == NoStroke)) + if (paintingDisabled()) return; if (npoints <= 1) @@ -491,8 +490,7 @@ void GraphicsContext::fillPath() CGContextRef context = platformContext(); switch (m_common->state.fillColorSpace) { case SolidColorSpace: - if (fillColor().alpha()) - fillPathWithFillRule(context, fillRule()); + fillPathWithFillRule(context, fillRule()); break; case PatternColorSpace: applyFillPattern(); @@ -519,8 +517,7 @@ void GraphicsContext::strokePath() CGContextRef context = platformContext(); switch (m_common->state.strokeColorSpace) { case SolidColorSpace: - if (strokeColor().alpha()) - CGContextStrokePath(context); + CGContextStrokePath(context); break; case PatternColorSpace: applyStrokePattern(); @@ -544,8 +541,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) CGContextRef context = platformContext(); switch (m_common->state.fillColorSpace) { case SolidColorSpace: - if (fillColor().alpha()) - CGContextFillRect(context, rect); + CGContextFillRect(context, rect); break; case PatternColorSpace: applyFillPattern(); @@ -565,20 +561,18 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) { if (paintingDisabled()) return; - if (color.alpha()) { - CGContextRef context = platformContext(); - Color oldFillColor = fillColor(); - if (oldFillColor != color) - setCGFillColor(context, color); - CGContextFillRect(context, rect); - if (oldFillColor != color) - setCGFillColor(context, oldFillColor); - } + CGContextRef context = platformContext(); + Color oldFillColor = fillColor(); + if (oldFillColor != color) + setCGFillColor(context, color); + CGContextFillRect(context, rect); + if (oldFillColor != color) + setCGFillColor(context, oldFillColor); } void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) { - if (paintingDisabled() || !color.alpha()) + if (paintingDisabled()) return; CGContextRef context = platformContext(); @@ -782,8 +776,7 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) CGContextRef context = platformContext(); switch (m_common->state.strokeColorSpace) { case SolidColorSpace: - if (strokeColor().alpha()) - CGContextStrokeRectWithWidth(context, r, lineWidth); + CGContextStrokeRectWithWidth(context, r, lineWidth); break; case PatternColorSpace: applyStrokePattern(); @@ -1199,4 +1192,3 @@ void GraphicsContext::setCompositeOperation(CompositeOperator mode) #endif } - diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp index c059985..7cb8799 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -33,10 +33,12 @@ #include "MIMETypeRegistry.h" #include "SharedBuffer.h" #include <ApplicationServices/ApplicationServices.h> +#include <wtf/UnusedParam.h> namespace WebCore { static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32"); +static const CFStringRef kCGImageSourceDoNotCacheImageBlocks = CFSTR("kCGImageSourceDoNotCacheImageBlocks"); ImageSource::ImageSource() : m_decoder(0) @@ -48,11 +50,24 @@ ImageSource::~ImageSource() clear(true); } -void ImageSource::clear(bool, size_t, SharedBuffer* data, bool allDataReceived) +void ImageSource::clear(bool destroyAllFrames, size_t, SharedBuffer* data, bool allDataReceived) { - // We always destroy the decoder, because there is no API to get it to - // selectively release some of the frames it's holding, and if we don't - // release any of them, we use too much memory on large images. +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + // Recent versions of ImageIO discard previously decoded image frames if the client + // application no longer holds references to them, so there's no need to throw away + // the decoder unless we're explicitly asked to destroy all of the frames. + + if (!destroyAllFrames) + return; +#else + // Older versions of ImageIO hold references to previously decoded image frames. + // There is no API to selectively release some of the frames it is holding, and + // if we don't release the frames we use too much memory on large images. + // Destroying the decoder is the only way to release previous frames. + + UNUSED_PARAM(destroyAllFrames); +#endif + if (m_decoder) { CFRelease(m_decoder); m_decoder = 0; @@ -66,9 +81,9 @@ static CFDictionaryRef imageSourceOptions() static CFDictionaryRef options; if (!options) { - const void* keys[2] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 }; - const void* values[2] = { kCFBooleanTrue, kCFBooleanTrue }; - options = CFDictionaryCreate(NULL, keys, values, 2, + const void* keys[3] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceDoNotCacheImageBlocks }; + const void* values[3] = { kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue }; + options = CFDictionaryCreate(NULL, keys, values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } return options; @@ -227,9 +242,17 @@ float ImageSource::frameDurationAtIndex(size_t index) bool ImageSource::frameHasAlphaAtIndex(size_t) { - // Might be interesting to do this optimization on Mac some day, but for now we're just using this - // for the Cairo source, since it uses our decoders, and our decoders can answer this question. - // FIXME: Could return false for JPEG and other non-transparent image formats. + if (!m_decoder) + return false; + + CFStringRef imageType = CGImageSourceGetType(m_decoder); + + // Return false if there is no image type or the image type is JPEG, because + // JPEG does not support alpha transparency. + if (!imageType || CFEqual(imageType, CFSTR("public.jpeg"))) + return false; + + // FIXME: Could return false for other non-transparent image formats. // FIXME: Could maybe return false for a GIF Frame if we have enough info in the GIF properties dictionary // to determine whether or not a transparent color was defined. return true; diff --git a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp index 129776e..bf1cd2e 100644 --- a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp @@ -414,14 +414,6 @@ FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& description) { FontDescription::GenericFamilyType generic = description.genericFamily(); - // FIXME: Mapping webkit generic to GenericFamilyType needs to - // be more intelligent. - // This spot rarely gets reached. GetFontDataForCharacters() gets hit a lot - // more often (see FIXME comment there). - const wchar_t* family = getFontFamilyForScript(description.dominantScript(), generic); - - if (family) - return getCachedFontPlatformData(description, AtomicString(family, wcslen(family))); // FIXME: Would be even better to somehow get the user's default font here. // For now we'll pick the default that the user would get without changing @@ -455,13 +447,6 @@ static LONG toGDIFontWeight(FontWeight fontWeight) return gdiFontWeights[fontWeight]; } -// FIXME: This may not be the best place to put this function -AtomicString FontCache::getGenericFontForScript(UScriptCode script, const FontDescription& description) -{ - const wchar_t* scriptFont = getFontFamilyForScript( script, description.genericFamily()); - return scriptFont ? AtomicString(scriptFont, wcslen(scriptFont)) : emptyAtom; -} - static void FillLogFont(const FontDescription& fontDescription, LOGFONT* winfont) { // The size here looks unusual. The negative number is intentional. diff --git a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp index 89433e1..797825e 100644 --- a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp @@ -46,6 +46,8 @@ #include "SkTypeface.h" #include "SkUtils.h" +#include <wtf/Assertions.h> + namespace WebCore { void FontCache::platformInit() @@ -79,9 +81,8 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, if (match) { FcChar8* family; if (FcPatternGetString(match, FC_FAMILY, 0, &family) == FcResultMatch) { - FontPlatformData* fpd = - createFontPlatformData(font.fontDescription(), AtomicString((char*) family)); - ret = new SimpleFontData(*fpd); + AtomicString fontFamily(reinterpret_cast<char*>(family)); + ret = getCachedFontData(getCachedFontPlatformData(font.fontDescription(), fontFamily, false)); } FcPatternDestroy(match); } @@ -98,8 +99,26 @@ FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& description) { - static AtomicString arialStr("Arial"); - return getCachedFontPlatformData(description, arialStr); + static const AtomicString sansStr("Sans"); + static const AtomicString serifStr("Serif"); + static const AtomicString monospaceStr("Monospace"); + + FontPlatformData* fontPlatformData = 0; + switch (description.genericFamily()) { + case FontDescription::SerifFamily: + fontPlatformData = getCachedFontPlatformData(description, serifStr); + break; + case FontDescription::MonospaceFamily: + fontPlatformData = getCachedFontPlatformData(description, monospaceStr); + break; + case FontDescription::SansSerifFamily: + default: + fontPlatformData = getCachedFontPlatformData(description, sansStr); + break; + } + + ASSERT(fontPlatformData); + return fontPlatformData; } void FontCache::getTraitsInFamily(const AtomicString& familyName, @@ -146,7 +165,13 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD if (fontDescription.italic()) style |= SkTypeface::kItalic; + // FIXME: This #ifdef can go away once we're firmly using the new Skia. + // During the transition, this makes the code compatible with both versions. +#ifdef SK_USE_OLD_255_TO_256 + SkTypeface* tf = SkTypeface::CreateFromName(name, static_cast<SkTypeface::Style>(style)); +#else SkTypeface* tf = SkTypeface::Create(name, static_cast<SkTypeface::Style>(style)); +#endif if (!tf) return 0; @@ -159,11 +184,4 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD return result; } -AtomicString FontCache::getGenericFontForScript(UScriptCode script, - const FontDescription& descript) -{ - notImplemented(); - return AtomicString(); -} - } // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index 1b71946..4710245 100644 --- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -249,10 +249,28 @@ bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs, // to subtract off the font ascent to get it. int x = lroundf(m_point.x() + startAdvance); int y = lroundf(m_point.y() - m_font->ascent()); + + // If there is a non-blur shadow and both the fill color and shadow color + // are opaque, handle without skia. + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (m_graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor)) { + // If there is a shadow and this code is reached, windowsCanHandleDrawTextShadow() + // will have already returned true during the ctor initiatization of m_useGDI + ASSERT(shadowColor.alpha() == 255); + ASSERT(m_graphicsContext->fillColor().alpha() == 255); + ASSERT(shadowBlur == 0); + COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue())); + COLORREF savedTextColor = GetTextColor(m_hdc); + SetTextColor(m_hdc, textColor); + ExtTextOut(m_hdc, x + shadowSize.width(), y + shadowSize.height(), ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]); + SetTextColor(m_hdc, savedTextColor); + } + return !!ExtTextOut(m_hdc, x, y, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]); } - class TransparencyAwareUniscribePainter : public TransparencyAwareFontPainter { public: TransparencyAwareUniscribePainter(GraphicsContext*, @@ -305,6 +323,10 @@ IntRect TransparencyAwareUniscribePainter::estimateTextBounds() UniscribeHelperTextRun state(m_run, *m_font); int left = lroundf(m_point.x()) + state.characterToX(m_from); int right = lroundf(m_point.x()) + state.characterToX(m_to); + + // Adjust for RTL script since we just want to know the text bounds. + if (left > right) + std::swap(left, right); // This algorithm for estimating how much extra space we need (the text may // go outside the selection rect) is based roughly on @@ -317,6 +339,11 @@ IntRect TransparencyAwareUniscribePainter::estimateTextBounds() } // namespace +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, @@ -416,6 +443,20 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, SetTextColor(hdc, skia::SkColorToCOLORREF(color)); SetBkMode(hdc, TRANSPARENT); + // If there is a non-blur shadow and both the fill color and shadow color + // are opaque, handle without skia. + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor) && windowsCanHandleDrawTextShadow(graphicsContext)) { + COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue())); + COLORREF savedTextColor = GetTextColor(hdc); + SetTextColor(hdc, textColor); + state.draw(graphicsContext, hdc, static_cast<int>(point.x()) + shadowSize.width(), + static_cast<int>(point.y() - ascent()) + shadowSize.height(), from, to); + SetTextColor(hdc, savedTextColor); + } + // Uniscribe counts the coordinates from the upper left, while WebKit uses // the baseline, so we have to subtract off the ascent. state.draw(graphicsContext, hdc, static_cast<int>(point.x()), @@ -424,7 +465,7 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, context->canvas()->endPlatformPaint(); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const { UniscribeHelperTextRun state(run, *this); return static_cast<float>(state.width()); diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp index 1e923ac..e99c12a 100644 --- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp @@ -116,7 +116,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b // Streams the concatenation of a header and font data. class EOTStream { public: - EOTStream(const Vector<uint8_t, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength) + EOTStream(const EOTHeader& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength) : m_eotHeader(eotHeader) , m_fontData(fontData) , m_overlayDst(overlayDst) @@ -130,7 +130,7 @@ public: size_t read(void* buffer, size_t count); private: - const Vector<uint8_t, 512>& m_eotHeader; + const EOTHeader& m_eotHeader; const SharedBuffer* m_fontData; size_t m_overlayDst; size_t m_overlaySrc; @@ -200,7 +200,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, // so we need to create an EOT header and prepend it to the font data. - Vector<uint8_t, 512> eotHeader; + EOTHeader eotHeader; size_t overlayDst; size_t overlaySrc; size_t overlayLength; diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp index 2b7c562..a952685 100644 --- a/WebCore/platform/graphics/chromium/FontLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -46,6 +46,11 @@ namespace WebCore { +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { @@ -111,7 +116,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, notImplemented(); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const { notImplemented(); return 0; diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp index 7b7d197..e6a61f6 100644 --- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp @@ -95,6 +95,11 @@ void FontPlatformData::setupPaint(SkPaint* paint) const paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); } +SkFontID FontPlatformData::uniqueID() const +{ + return m_typeface->uniqueID(); +} + bool FontPlatformData::operator==(const FontPlatformData& a) const { // If either of the typeface pointers are invalid (either NULL or the diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h index ec7d837..c63a860 100644 --- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h @@ -36,6 +36,7 @@ class SkPaint; class SkTypeface; +typedef uint32_t SkFontID; namespace WebCore { @@ -90,6 +91,12 @@ public: // ------------------------------------------------------------------------- void setupPaint(SkPaint*) const; + // ------------------------------------------------------------------------- + // Return Skia's unique id for this font. This encodes both the style and + // the font's file name so refers to a single face. + // ------------------------------------------------------------------------- + SkFontID uniqueID() const; + unsigned hash() const; float size() const { return m_textSize; } diff --git a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp index ed326c8..9596a4c 100644 --- a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp @@ -120,6 +120,52 @@ void initializeScriptFontMap(ScriptToFontMap& scriptFontMap) scriptFontMap[USCRIPT_HAN] = localeFamily; } +// There are a lot of characters in USCRIPT_COMMON that can be covered +// by fonts for scripts closely related to them. See +// http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:Script=Common:] +// FIXME: make this more efficient with a wider coverage +UScriptCode getScriptBasedOnUnicodeBlock(int ucs4) +{ + UBlockCode block = ublock_getCode(ucs4); + switch (block) { + case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: + return USCRIPT_HAN; + case UBLOCK_HIRAGANA: + case UBLOCK_KATAKANA: + return USCRIPT_HIRAGANA; + case UBLOCK_ARABIC: + return USCRIPT_ARABIC; + case UBLOCK_THAI: + return USCRIPT_THAI; + case UBLOCK_GREEK: + return USCRIPT_GREEK; + case UBLOCK_DEVANAGARI: + // For Danda and Double Danda (U+0964, U+0965), use a Devanagari + // font for now although they're used by other scripts as well. + // Without a context, we can't do any better. + return USCRIPT_DEVANAGARI; + case UBLOCK_ARMENIAN: + return USCRIPT_ARMENIAN; + case UBLOCK_GEORGIAN: + return USCRIPT_GEORGIAN; + case UBLOCK_KANNADA: + return USCRIPT_KANNADA; + default: + return USCRIPT_COMMON; + } +} + +UScriptCode getScript(int ucs4) +{ + UErrorCode err = U_ZERO_ERROR; + UScriptCode script = uscript_getScript(ucs4, &err); + // If script is invalid, common or inherited or there's an error, + // infer a script based on the unicode block of a character. + if (script <= USCRIPT_INHERITED || U_FAILURE(err)) + script = getScriptBasedOnUnicodeBlock(ucs4); + return script; +} + const int kUndefinedAscent = std::numeric_limits<int>::min(); // Given an HFONT, return the ascent. If GetTextMetrics fails, @@ -209,11 +255,9 @@ const UChar* getFallbackFamily(const UChar* characters, // to get a font required to render the string. int i = 0; UChar32 ucs4 = 0; - while (i < length && script == USCRIPT_COMMON || script == USCRIPT_INVALID_CODE) { + while (i < length && script == USCRIPT_COMMON) { U16_NEXT(characters, i, length, ucs4); - UErrorCode err = U_ZERO_ERROR; - script = uscript_getScript(ucs4, &err); - // silently ignore the error + script = getScript(ucs4); } // For the full-width ASCII characters (U+FF00 - U+FF5E), use the font for @@ -223,46 +267,8 @@ const UChar* getFallbackFamily(const UChar* characters, if (0xFF00 < ucs4 && ucs4 < 0xFF5F) script = USCRIPT_HAN; - // There are a lot of characters in USCRIPT_COMMON that can be covered - // by fonts for scripts closely related to them. See - // http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:Script=Common:] - // FIXME: make this more efficient with a wider coverage - if (script == USCRIPT_COMMON || script == USCRIPT_INHERITED) { - UBlockCode block = ublock_getCode(ucs4); - switch (block) { - case UBLOCK_BASIC_LATIN: - script = USCRIPT_LATIN; - break; - case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: - script = USCRIPT_HAN; - break; - case UBLOCK_HIRAGANA: - case UBLOCK_KATAKANA: - script = USCRIPT_HIRAGANA; - break; - case UBLOCK_ARABIC: - script = USCRIPT_ARABIC; - break; - case UBLOCK_GREEK: - script = USCRIPT_GREEK; - break; - case UBLOCK_DEVANAGARI: - // For Danda and Double Danda (U+0964, U+0965), use a Devanagari - // font for now although they're used by other scripts as well. - // Without a context, we can't do any better. - script = USCRIPT_DEVANAGARI; - break; - case UBLOCK_ARMENIAN: - script = USCRIPT_ARMENIAN; - break; - case UBLOCK_GEORGIAN: - script = USCRIPT_GEORGIAN; - break; - case UBLOCK_KANNADA: - script = USCRIPT_KANNADA; - break; - } - } + if (script == USCRIPT_COMMON) + script = getScriptBasedOnUnicodeBlock(ucs4); // Another lame work-around to cover non-BMP characters. const UChar* family = getFontFamilyForScript(script, generic); diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp index 31c5256..2cb1cc5 100644 --- a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp @@ -72,7 +72,7 @@ static bool fillBMPGlyphs(unsigned offset, bool recurse) { HDC dc = GetDC((HWND)0); - HGDIOBJ oldFont = SelectObject(dc, fontData->m_font.hfont()); + HGDIOBJ oldFont = SelectObject(dc, fontData->platformData().hfont()); TEXTMETRIC tm = {0}; if (!GetTextMetrics(dc, &tm)) { @@ -80,7 +80,7 @@ static bool fillBMPGlyphs(unsigned offset, ReleaseDC(0, dc); if (recurse) { - if (ChromiumBridge::ensureFontLoaded(fontData->m_font.hfont())) + if (ChromiumBridge::ensureFontLoaded(fontData->platformData().hfont())) return fillBMPGlyphs(offset, length, buffer, page, fontData, false); else { fillEmptyGlyphs(page); @@ -191,9 +191,9 @@ static bool fillNonBMPGlyphs(unsigned offset, bool haveGlyphs = false; UniscribeHelperTextRun state(buffer, length * 2, false, - fontData->m_font.hfont(), - fontData->m_font.scriptCache(), - fontData->m_font.scriptFontProperties()); + fontData->platformData().hfont(), + fontData->platformData().scriptCache(), + fontData->platformData().scriptFontProperties()); state.setInhibitLigate(true); state.setDisableFontFallback(true); state.init(); diff --git a/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h index e8ba0ad..534244d 100644 --- a/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h +++ b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h @@ -37,67 +37,12 @@ namespace WebCore { -class MediaPlayerPrivate : public MediaPlayerPrivateInterface { +class MediaPlayerPrivate { public: static void registerMediaEngine(MediaEngineRegistrar); - ~MediaPlayerPrivate(); - - IntSize naturalSize() const; - bool hasVideo() const; - - void load(const String& url); - void cancelLoad(); - - void play(); - void pause(); - - bool paused() const; - bool seeking() const; - - float duration() const; - float currentTime() const; - void seek(float time); - void setEndTime(float); - - void setRate(float); - void setVolume(float); - - int dataRate() const; - - MediaPlayer::NetworkState networkState() const; - MediaPlayer::ReadyState readyState() const; - - float maxTimeBuffered() const; - float maxTimeSeekable() const; - unsigned bytesLoaded() const; - bool totalBytesKnown() const; - unsigned totalBytes() const; - - void setVisible(bool); - void setSize(const IntSize&); - - void paint(GraphicsContext*, const IntRect&); - - // Public methods to be called by WebMediaPlayer - FrameView* frameView(); - void networkStateChanged(); - void readyStateChanged(); - void timeChanged(); - void volumeChanged(); - void repaint(); - -private: - MediaPlayerPrivate(MediaPlayer*); - static MediaPlayerPrivateInterface* create(MediaPlayer* player); - static void getSupportedTypes(HashSet<String>&); - static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); - static bool isAvailable(); - - MediaPlayer* m_player; - void* m_data; }; -} // namespace WebCore +} // namespace WebCore #endif diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp index 06e997f..6f5ce90 100644 --- a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp @@ -54,11 +54,11 @@ static inline float scaleEmToUnits(float x, int unitsPerEm) void SimpleFontData::platformInit() { HDC dc = GetDC(0); - HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); TEXTMETRIC textMetric = {0}; if (!GetTextMetrics(dc, &textMetric)) { - if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) { + if (ChromiumBridge::ensureFontLoaded(m_platformData.hfont())) { // Retry GetTextMetrics. // FIXME: Handle gracefully the error if this call also fails. // See http://crbug.com/6401. @@ -91,6 +91,11 @@ void SimpleFontData::platformInit() ReleaseDC(0, dc); } +void SimpleFontData::platformCharWidthInit() +{ + // charwidths are set in platformInit. +} + void SimpleFontData::platformDestroy() { // We don't hash this on Win32, so it's effectively owned by us. @@ -102,7 +107,7 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes { if (!m_smallCapsFontData) { LOGFONT winFont; - GetObject(m_font.hfont(), sizeof(LOGFONT), &winFont); + GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winFont); float smallCapsSize = 0.70f * fontDescription.computedSize(); // Unlike WebKit trunk, we don't multiply the size by 32. That seems // to be some kind of artifact of their CG backend, or something. @@ -125,13 +130,13 @@ void SimpleFontData::determinePitch() { // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that. HDC dc = GetDC(0); - HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); // Yes, this looks backwards, but the fixed pitch bit is actually set if the font // is *not* fixed pitch. Unbelievable but true. TEXTMETRIC textMetric = {0}; if (!GetTextMetrics(dc, &textMetric)) { - if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) { + if (ChromiumBridge::ensureFontLoaded(m_platformData.hfont())) { // Retry GetTextMetrics. // FIXME: Handle gracefully the error if this call also fails. // See http://crbug.com/6401. @@ -149,12 +154,12 @@ void SimpleFontData::determinePitch() float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { HDC dc = GetDC(0); - HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); int width = 0; if (!GetCharWidthI(dc, glyph, 1, 0, &width)) { // Ask the browser to preload the font and retry. - if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) { + if (ChromiumBridge::ensureFontLoaded(m_platformData.hfont())) { // FIXME: Handle gracefully the error if this call also fails. // See http://crbug.com/6401. if (!GetCharWidthI(dc, glyph, 1, 0, &width)) diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp index 8200175..3bff83f 100644 --- a/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp +++ b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp @@ -36,33 +36,54 @@ #include "FloatRect.h" #include "FontDescription.h" #include "Logging.h" -#include "NotImplemented.h" +#include "VDMXParser.h" +#include "SkFontHost.h" #include "SkPaint.h" -#include "SkTypeface.h" #include "SkTime.h" +#include "SkTypeface.h" +#include "SkTypes.h" namespace WebCore { // Smallcaps versions of fonts are 70% the size of the normal font. static const float smallCapsFraction = 0.7f; +// This is the largest VDMX table which we'll try to load and parse. +static const size_t maxVDMXTableSize = 1024 * 1024; // 1 MB void SimpleFontData::platformInit() { SkPaint paint; SkPaint::FontMetrics metrics; - m_font.setupPaint(&paint); + m_platformData.setupPaint(&paint); paint.getFontMetrics(&metrics); + const SkFontID fontID = m_platformData.uniqueID(); + + static const uint32_t vdmxTag = SkSetFourByteTag('V', 'D', 'M', 'X'); + int pixelSize = m_platformData.size() + 0.5; + int vdmxAscent, vdmxDescent; + bool isVDMXValid = false; + + size_t vdmxSize = SkFontHost::GetTableSize(fontID, vdmxTag); + if (vdmxSize && vdmxSize < maxVDMXTableSize) { + uint8_t* vdmxTable = (uint8_t*) fastMalloc(vdmxSize); + if (vdmxTable + && SkFontHost::GetTableData(fontID, vdmxTag, 0, vdmxSize, vdmxTable) == vdmxSize + && parseVDMX(&vdmxAscent, &vdmxDescent, vdmxTable, vdmxSize, pixelSize)) + isVDMXValid = true; + fastFree(vdmxTable); + } // Beware those who step here: This code is designed to match Win32 font // metrics *exactly*. - if (metrics.fVDMXMetricsValid) { - m_ascent = metrics.fVDMXAscent; - m_descent = metrics.fVDMXDescent; + if (isVDMXValid) { + m_ascent = vdmxAscent; + m_descent = -vdmxDescent; } else { + SkScalar height = -metrics.fAscent + metrics.fDescent + metrics.fLeading; m_ascent = SkScalarRound(-metrics.fAscent); - m_descent = SkScalarRound(metrics.fHeight) - m_ascent; + m_descent = SkScalarRound(height) - m_ascent; } if (metrics.fXHeight) @@ -79,7 +100,8 @@ void SimpleFontData::platformInit() // calculated for us, but we need to calculate m_maxCharWidth and // m_avgCharWidth in order for text entry widgets to be sized correctly. - m_maxCharWidth = SkScalarRound(metrics.fXRange * SkScalarRound(m_font.size())); + SkScalar xRange = metrics.fXMax - metrics.fXMin; + m_maxCharWidth = SkScalarRound(xRange * SkScalarRound(m_platformData.size())); if (metrics.fAvgCharWidth) m_avgCharWidth = SkScalarRound(metrics.fAvgCharWidth); @@ -98,6 +120,11 @@ void SimpleFontData::platformInit() } } +void SimpleFontData::platformCharWidthInit() +{ + // charwidths are set in platformInit. +} + void SimpleFontData::platformDestroy() { delete m_smallCapsFontData; @@ -108,7 +135,7 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes { if (!m_smallCapsFontData) { const float smallCapsSize = lroundf(fontDescription.computedSize() * smallCapsFraction); - m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_font, smallCapsSize)); + m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_platformData, smallCapsSize)); } return m_smallCapsFontData; @@ -120,7 +147,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con static const unsigned maxBufferCount = 64; uint16_t glyphs[maxBufferCount]; - m_font.setupPaint(&paint); + m_platformData.setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); while (length > 0) { @@ -151,11 +178,11 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const SkPaint paint; - m_font.setupPaint(&paint); + m_platformData.setupPaint(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); SkScalar width = paint.measureText(&glyph, 2); - + return SkScalarToFloat(width); } diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/WebCore/platform/graphics/chromium/TransparencyWin.cpp index 8c790af..d3ced81 100644 --- a/WebCore/platform/graphics/chromium/TransparencyWin.cpp +++ b/WebCore/platform/graphics/chromium/TransparencyWin.cpp @@ -109,7 +109,7 @@ class TransparencyWin::OwnedBuffers { public: OwnedBuffers(const IntSize& size, bool needReferenceBuffer) { - m_destBitmap.adopt(ImageBuffer::create(size, false)); + m_destBitmap = ImageBuffer::create(size, false); if (needReferenceBuffer) { m_referenceBitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height()); diff --git a/WebCore/platform/graphics/chromium/VDMXParser.cpp b/WebCore/platform/graphics/chromium/VDMXParser.cpp new file mode 100644 index 0000000..3347226 --- /dev/null +++ b/WebCore/platform/graphics/chromium/VDMXParser.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +// For htons/ntohs +#include <arpa/inet.h> + +// Buffer helper class +// +// This class perform some trival buffer operations while checking for +// out-of-bounds errors. As a family they return false if anything is amiss, +// updating the current offset otherwise. +class Buffer { +public: + Buffer(const uint8_t* buffer, size_t length) + : m_buffer(buffer) + , m_length(length) + , m_offset(0) { } + + bool skip(size_t numBytes) + { + if (m_offset + numBytes > m_length) + return false; + m_offset += numBytes; + return true; + } + + bool readU8(uint8_t* value) + { + if (m_offset + sizeof(uint8_t) > m_length) + return false; + *value = m_buffer[m_offset]; + m_offset += sizeof(uint8_t); + return true; + } + + bool readU16(uint16_t* value) + { + if (m_offset + sizeof(uint16_t) > m_length) + return false; + memcpy(value, m_buffer + m_offset, sizeof(uint16_t)); + *value = ntohs(*value); + m_offset += sizeof(uint16_t); + return true; + } + + bool readS16(int16_t* value) + { + return readU16(reinterpret_cast<uint16_t*>(value)); + } + + size_t offset() const + { + return m_offset; + } + + void setOffset(size_t newoffset) + { + m_offset = newoffset; + } + +private: + const uint8_t *const m_buffer; + const size_t m_length; + size_t m_offset; +}; + +// VDMX parsing code. +// +// VDMX tables are found in some TrueType/OpenType fonts and contain +// ascender/descender overrides for certain (usually small) sizes. This is +// needed in order to match font metrics on Windows. +// +// Freetype does not parse these tables so we do so here. + +namespace WebCore { + +// Parse a TrueType VDMX table. +// yMax: (output) the ascender value from the table +// yMin: (output) the descender value from the table (negative!) +// vdmx: the table bytes +// vdmxLength: length of @vdmx, in bytes +// targetPixelSize: the pixel size of the font (e.g. 16) +// +// Returns true iff a suitable match are found. Otherwise, *yMax and *yMin are +// untouched. size_t must be 32-bits to avoid overflow. +// +// See http://www.microsoft.com/opentype/otspec/vdmx.htm +bool parseVDMX(int* yMax, int* yMin, + const uint8_t* vdmx, size_t vdmxLength, + unsigned targetPixelSize) +{ + Buffer buf(vdmx, vdmxLength); + + // We ignore the version. Future tables should be backwards compatible with + // this layout. + uint16_t numRatios; + if (!buf.skip(4) || !buf.readU16(&numRatios)) + return false; + + // Now we have two tables. Firstly we have @numRatios Ratio records, then a + // matching array of @numRatios offsets. We save the offset of the beginning + // of this second table. + // + // Range 6 <= x <= 262146 + unsigned long offsetTableOffset = + buf.offset() + 4 /* sizeof struct ratio */ * numRatios; + + unsigned desiredRatio = 0xffffffff; + // We read 4 bytes per record, so the offset range is + // 6 <= x <= 524286 + for (unsigned i = 0; i < numRatios; ++i) { + uint8_t xRatio, yRatio1, yRatio2; + + if (!buf.skip(1) + || !buf.readU8(&xRatio) + || !buf.readU8(&yRatio1) + || !buf.readU8(&yRatio2)) + return false; + + // This either covers 1:1, or this is the default entry (0, 0, 0) + if ((xRatio == 1 && yRatio1 <= 1 && yRatio2 >= 1) + || (xRatio == 0 && yRatio1 == 0 && yRatio2 == 0)) { + desiredRatio = i; + break; + } + } + + if (desiredRatio == 0xffffffff) // no ratio found + return false; + + // Range 10 <= x <= 393216 + buf.setOffset(offsetTableOffset + sizeof(uint16_t) * desiredRatio); + + // Now we read from the offset table to get the offset of another array + uint16_t groupOffset; + if (!buf.readU16(&groupOffset)) + return false; + // Range 0 <= x <= 65535 + buf.setOffset(groupOffset); + + uint16_t numRecords; + if (!buf.readU16(&numRecords) || !buf.skip(sizeof(uint16_t))) + return false; + + // We read 6 bytes per record, so the offset range is + // 4 <= x <= 458749 + for (unsigned i = 0; i < numRecords; ++i) { + uint16_t pixelSize; + if (!buf.readU16(&pixelSize)) + return false; + // the entries are sorted, so we can abort early if need be + if (pixelSize > targetPixelSize) + return false; + + if (pixelSize == targetPixelSize) { + int16_t tempYMax, tempYMin; + if (!buf.readS16(&tempYMax) + || !buf.readS16(&tempYMin)) + return false; + *yMin = tempYMin; + *yMax = tempYMax; + return true; + } + if (!buf.skip(2 * sizeof(int16_t))) + return false; + } + + return false; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/VDMXParser.h b/WebCore/platform/graphics/chromium/VDMXParser.h new file mode 100644 index 0000000..ef625b7 --- /dev/null +++ b/WebCore/platform/graphics/chromium/VDMXParser.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef VDMXParser_h +#define VDMXParser_h + +namespace WebCore { + bool parseVDMX(int* ymax, int* ymin, + const uint8_t* vdmx, size_t vdmxLength, + unsigned targetPixelSize); +} // namespace WebCore + +#endif diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp index 7210367..86b702f 100644 --- a/WebCore/platform/graphics/filters/FEBlend.cpp +++ b/WebCore/platform/graphics/filters/FEBlend.cpp @@ -21,9 +21,11 @@ #include "config.h" -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FEBlend.h" +#include "Filter.h" + namespace WebCore { FEBlend::FEBlend(FilterEffect* in, FilterEffect* in2, BlendModeType mode) @@ -59,7 +61,7 @@ void FEBlend::setBlendMode(BlendModeType mode) m_mode = mode; } -void FEBlend::apply() +void FEBlend::apply(Filter*) { } @@ -69,4 +71,4 @@ void FEBlend::dump() } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEBlend.h b/WebCore/platform/graphics/filters/FEBlend.h index b2835e8..dec04ac 100644 --- a/WebCore/platform/graphics/filters/FEBlend.h +++ b/WebCore/platform/graphics/filters/FEBlend.h @@ -22,9 +22,11 @@ #ifndef SVGFEBlend_h #define SVGFEBlend_h -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FilterEffect.h" +#include "Filter.h" + namespace WebCore { enum BlendModeType { @@ -46,8 +48,8 @@ namespace WebCore { BlendModeType blendMode() const; void setBlendMode(BlendModeType); - virtual void apply(); - virtual void dump(); + void apply(Filter*); + void dump(); private: FEBlend(FilterEffect*, FilterEffect*, BlendModeType); @@ -59,6 +61,6 @@ namespace WebCore { } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) #endif // SVGFEBlend_h diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp index f783106..8704e64 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -21,9 +21,11 @@ #include "config.h" -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FEColorMatrix.h" +#include "Filter.h" + namespace WebCore { FEColorMatrix::FEColorMatrix(FilterEffect* in, ColorMatrixType type, const Vector<float>& values) @@ -59,7 +61,7 @@ void FEColorMatrix::setValues(const Vector<float> &values) m_values = values; } -void FEColorMatrix::apply() +void FEColorMatrix::apply(Filter*) { } @@ -69,4 +71,4 @@ void FEColorMatrix::dump() } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.h b/WebCore/platform/graphics/filters/FEColorMatrix.h index d8193ed..eeb3557 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.h +++ b/WebCore/platform/graphics/filters/FEColorMatrix.h @@ -22,8 +22,10 @@ #ifndef SVGFEColorMatrix_h #define SVGFEColorMatrix_h -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FilterEffect.h" + +#include "Filter.h" #include <wtf/Vector.h> namespace WebCore { @@ -46,8 +48,8 @@ namespace WebCore { const Vector<float>& values() const; void setValues(const Vector<float>&); - virtual void apply(); - virtual void dump(); + void apply(Filter*); + void dump(); private: FEColorMatrix(FilterEffect*, ColorMatrixType, const Vector<float>&); @@ -59,6 +61,6 @@ namespace WebCore { } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) #endif // SVGFEColorMatrix_h diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp index 708ea3e..54ac123 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp @@ -21,9 +21,11 @@ #include "config.h" -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FEComponentTransfer.h" +#include "Filter.h" + namespace WebCore { FEComponentTransfer::FEComponentTransfer(FilterEffect* in, const ComponentTransferFunction& redFunc, @@ -83,7 +85,7 @@ void FEComponentTransfer::setAlphaFunction(const ComponentTransferFunction& func m_alphaFunc = func; } -void FEComponentTransfer::apply() +void FEComponentTransfer::apply(Filter*) { } @@ -93,4 +95,4 @@ void FEComponentTransfer::dump() } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.h b/WebCore/platform/graphics/filters/FEComponentTransfer.h index 20d70c0..cc1d1f8 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.h +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.h @@ -22,10 +22,11 @@ #ifndef SVGFEComponentTransfer_h #define SVGFEComponentTransfer_h -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FilterEffect.h" -#include "SVGFEDisplacementMap.h" +#include "SVGFEDisplacementMap.h" +#include "Filter.h" #include <wtf/Vector.h> namespace WebCore { @@ -78,8 +79,8 @@ namespace WebCore { ComponentTransferFunction alphaFunction() const; void setAlphaFunction(const ComponentTransferFunction&); - virtual void apply(); - virtual void dump(); + void apply(Filter*); + void dump(); private: FEComponentTransfer(FilterEffect*,const ComponentTransferFunction&, const ComponentTransferFunction&, @@ -94,6 +95,6 @@ namespace WebCore { } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) #endif // SVGFEComponentTransfer_h diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp index 0b5ce94..0706358 100644 --- a/WebCore/platform/graphics/filters/FEComposite.cpp +++ b/WebCore/platform/graphics/filters/FEComposite.cpp @@ -21,9 +21,11 @@ #include "config.h" -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FEComposite.h" +#include "Filter.h" + namespace WebCore { FEComposite::FEComposite(FilterEffect* in, FilterEffect* in2, const CompositeOperationType& type, @@ -95,7 +97,7 @@ void FEComposite::setK4(float k4) m_k4 = k4; } -void FEComposite::apply() +void FEComposite::apply(Filter*) { } @@ -105,4 +107,4 @@ void FEComposite::dump() } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FEComposite.h b/WebCore/platform/graphics/filters/FEComposite.h index d205395..b623cce 100644 --- a/WebCore/platform/graphics/filters/FEComposite.h +++ b/WebCore/platform/graphics/filters/FEComposite.h @@ -22,9 +22,11 @@ #ifndef SVGFEComposite_h #define SVGFEComposite_h -#if ENABLE(SVG) && ENABLE(SVG_FILTERS) +#if ENABLE(FILTERS) #include "FilterEffect.h" + #include "PlatformString.h" +#include "Filter.h" namespace WebCore { @@ -58,8 +60,8 @@ namespace WebCore { float k4() const; void setK4(float); - virtual void apply(); - virtual void dump(); + void apply(Filter*); + void dump(); private: FEComposite(FilterEffect*, FilterEffect*, const CompositeOperationType&, @@ -76,6 +78,6 @@ namespace WebCore { } // namespace WebCore -#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS) +#endif // ENABLE(FILTERS) #endif // SVGFEComposite_h diff --git a/WebCore/platform/graphics/filters/Filter.h b/WebCore/platform/graphics/filters/Filter.h new file mode 100644 index 0000000..84909da --- /dev/null +++ b/WebCore/platform/graphics/filters/Filter.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * aint with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef Filter_h +#define Filter_h + +#if ENABLE(FILTERS) +#include "Image.h" +#include "StringHash.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class FilterEffect; + + class Filter : public RefCounted<Filter> { + public: + virtual ~Filter() { } + + void setSourceImage(PassRefPtr<Image> image) { m_image = image; } + Image* sourceImage() { return m_image.get(); } + + virtual void calculateEffectSubRegion(FilterEffect*) = 0; + + private: + RefPtr<Image> m_image; + }; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // Filter_h diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp new file mode 100644 index 0000000..cd74992 --- /dev/null +++ b/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -0,0 +1,46 @@ +/* + Copyright (C) Alex Mathews <possessedpenguinbob@gmail.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "FilterEffect.h" + +namespace WebCore { + +FilterEffect::FilterEffect() + : m_xBBoxMode(false) + , m_yBBoxMode(false) + , m_widthBBoxMode(false) + , m_heightBBoxMode(false) +{ +} + +FilterEffect::~FilterEffect() +{ +} + +TextStream& FilterEffect::externalRepresentation(TextStream& ts) const +{ + return ts; +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h new file mode 100644 index 0000000..e2a058d --- /dev/null +++ b/WebCore/platform/graphics/filters/FilterEffect.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + 2009 Dirk Schulze <krit@webkit.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef FilterEffect_h +#define FilterEffect_h + +#if ENABLE(FILTERS) +#include "Filter.h" +#include "FloatRect.h" +#include "ImageBuffer.h" +#include "TextStream.h" + +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class FilterEffect : public RefCounted<FilterEffect> { + public: + virtual ~FilterEffect(); + + bool xBoundingBoxMode() const { return m_xBBoxMode; } + void setXBoundingBoxMode(bool bboxMode) { m_xBBoxMode = bboxMode; } + + bool yBoundingBoxMode() const { return m_yBBoxMode; } + void setYBoundingBoxMode(bool bboxMode) { m_yBBoxMode = bboxMode; } + + bool widthBoundingBoxMode() const { return m_widthBBoxMode; } + void setWidthBoundingBoxMode(bool bboxMode) { m_widthBBoxMode = bboxMode; } + + bool heightBoundingBoxMode() const { return m_heightBBoxMode; } + void setHeightBoundingBoxMode(bool bboxMode) { m_heightBBoxMode = bboxMode; } + + FloatRect subRegion() const { return m_subRegion; } + void setSubRegion(const FloatRect& subRegion) { m_subRegion = subRegion; } + + // The result is bounded by the size of the filter primitive to save resources + ImageBuffer* resultImage() { return m_effectBuffer.get(); } + void setEffectBuffer(ImageBuffer* effectBuffer) { m_effectBuffer.set(effectBuffer); } + + virtual void apply(Filter*) = 0; + virtual void dump() = 0; + + virtual TextStream& externalRepresentation(TextStream&) const; + protected: + FilterEffect(); + + private: + + bool m_xBBoxMode : 1; + bool m_yBBoxMode : 1; + bool m_widthBBoxMode : 1; + bool m_heightBBoxMode : 1; + + FloatRect m_subRegion; + + mutable OwnPtr<ImageBuffer> m_effectBuffer; + }; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // FilterEffect_h diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp new file mode 100644 index 0000000..646a57b --- /dev/null +++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * aint with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "SourceAlpha.h" + +#include "GraphicsContext.h" +#include "PlatformString.h" +#include "Filter.h" + +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +PassRefPtr<SourceAlpha> SourceAlpha::create() +{ + return adoptRef(new SourceAlpha); +} + +const AtomicString& SourceAlpha::effectName() +{ + DEFINE_STATIC_LOCAL(const AtomicString, s_effectName, ("SourceAlpha")); + return s_effectName; +} + +void SourceAlpha::apply(Filter*) +{ +} + +void SourceAlpha::dump() +{ +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/SourceAlpha.h b/WebCore/platform/graphics/filters/SourceAlpha.h new file mode 100644 index 0000000..21497aa --- /dev/null +++ b/WebCore/platform/graphics/filters/SourceAlpha.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SourceAlpha_h +#define SourceAlpha_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" + +#include "PlatformString.h" +#include "Filter.h" + +namespace WebCore { + + class SourceAlpha : public FilterEffect { + public: + static PassRefPtr<SourceAlpha> create(); + + static const AtomicString& effectName(); + + void apply(Filter*); + void dump(); + + private: + SourceAlpha() { } + }; +} //namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // SourceAlpha_h diff --git a/WebCore/platform/graphics/filters/SourceGraphic.cpp b/WebCore/platform/graphics/filters/SourceGraphic.cpp new file mode 100644 index 0000000..39d4810 --- /dev/null +++ b/WebCore/platform/graphics/filters/SourceGraphic.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * aint with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(FILTERS) +#include "SourceGraphic.h" + +#include "GraphicsContext.h" +#include "PlatformString.h" +#include "Filter.h" + +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +PassRefPtr<SourceGraphic> SourceGraphic::create() +{ + return adoptRef(new SourceGraphic); +} + +const AtomicString& SourceGraphic::effectName() +{ + DEFINE_STATIC_LOCAL(const AtomicString, s_effectName, ("SourceGraphic")); + return s_effectName; +} + +void SourceGraphic::apply(Filter*) +{ +} + +void SourceGraphic::dump() +{ +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/SourceGraphic.h b/WebCore/platform/graphics/filters/SourceGraphic.h new file mode 100644 index 0000000..363fb97 --- /dev/null +++ b/WebCore/platform/graphics/filters/SourceGraphic.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2008 Alex Mathews <possessedpenguinbob@gmail.com> + 2009 Dirk Schulze <krit@webkit.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef SourceGraphic_h +#define SourceGrahpic_h + +#if ENABLE(FILTERS) +#include "FilterEffect.h" + +#include "PlatformString.h" +#include "Filter.h" + +namespace WebCore { + + class SourceGraphic : public FilterEffect { + public: + static PassRefPtr<SourceGraphic> create(); + + static const AtomicString& effectName(); + + void apply(Filter*); + void dump(); + + private: + SourceGraphic() { } + }; +} //namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // SourceGraphic_h diff --git a/WebCore/platform/graphics/gtk/FontCacheGtk.cpp b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp index d2b43cc..e0b88da 100644 --- a/WebCore/platform/graphics/gtk/FontCacheGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp @@ -37,7 +37,7 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, cons { #if defined(USE_FREETYPE) FcResult fresult; - FontPlatformData* prim = const_cast<FontPlatformData*>(&font.primaryFont()->m_font); + FontPlatformData* prim = const_cast<FontPlatformData*>(&font.primaryFont()->platformData()); if (!prim->m_fallbacks) prim->m_fallbacks = FcFontSort(NULL, prim->m_pattern, FcTrue, NULL, &fresult); diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp index 288ba91..6561f02 100644 --- a/WebCore/platform/graphics/gtk/FontGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -34,7 +34,6 @@ #include "Font.h" #include "GraphicsContext.h" -#include "NotImplemented.h" #include "SimpleFontData.h" #include <cairo.h> @@ -145,14 +144,14 @@ static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int fro static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout* layout) { #if defined(USE_FREETYPE) - if (font->primaryFont()->m_font.m_pattern) { - PangoFontDescription* desc = pango_fc_font_description_from_pattern(font->primaryFont()->m_font.m_pattern, FALSE); + if (font->primaryFont()->platformData().m_pattern) { + PangoFontDescription* desc = pango_fc_font_description_from_pattern(font->primaryFont()->platformData().m_pattern, FALSE); pango_layout_set_font_description(layout, desc); pango_font_description_free(desc); } #elif defined(USE_PANGO) - if (font->primaryFont()->m_font.m_font) { - PangoFontDescription* desc = pango_font_describe(font->primaryFont()->m_font.m_font); + if (font->primaryFont()->platformData().m_font) { + PangoFontDescription* desc = pango_font_describe(font->primaryFont()->platformData().m_font); pango_layout_set_font_description(layout, desc); pango_font_description_free(desc); } @@ -183,6 +182,11 @@ static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout pango_attr_list_unref(list); } +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { cairo_t* cr = context->platformContext(); @@ -290,7 +294,7 @@ static PangoLayout* getDefaultPangoLayout(const TextRun& run) return layout; } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const { if (run.length() == 0) return 0.0f; diff --git a/WebCore/platform/graphics/gtk/FontPlatformData.h b/WebCore/platform/graphics/gtk/FontPlatformData.h index 20c52e5..ae1f134 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformData.h +++ b/WebCore/platform/graphics/gtk/FontPlatformData.h @@ -82,6 +82,8 @@ public: bool isFixedPitch(); float size() const { return m_size; } + bool syntheticBold() const { return m_syntheticBold; } + bool syntheticOblique() const { return m_syntheticOblique; } void setFont(cairo_t*) const; diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp index 68685e9..f0f0dd5 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp @@ -109,10 +109,9 @@ FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const cairo_matrix_init_scale(&fontMatrix, fontDescription.computedPixelSize(), fontDescription.computedPixelSize()); cairo_matrix_init_identity(&ctm); -#if GTK_CHECK_VERSION(2,10,0) if (GdkScreen* screen = gdk_screen_get_default()) options = gdk_screen_get_font_options(screen); -#endif + // gdk_screen_get_font_options() returns NULL if no default options are // set, so we always have to check. if (!options) @@ -150,10 +149,9 @@ FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool b static const cairo_font_options_t* defaultOptions = cairo_font_options_create(); const cairo_font_options_t* options = NULL; -#if GTK_CHECK_VERSION(2,10,0) if (GdkScreen* screen = gdk_screen_get_default()) options = gdk_screen_get_font_options(screen); -#endif + // gdk_screen_get_font_options() returns NULL if no default options are // set, so we always have to check. if (!options) diff --git a/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp b/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp index 24ad864..7c9ffe6 100644 --- a/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp +++ b/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp @@ -42,7 +42,7 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b if (bufferLength > GlyphPage::size) return false; - FT_Face face = cairo_ft_scaled_font_lock_face(fontData->m_font.m_scaledFont); + FT_Face face = cairo_ft_scaled_font_lock_face(fontData->platformData().m_scaledFont); if (!face) return false; @@ -57,7 +57,7 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b } } - cairo_ft_scaled_font_unlock_face(fontData->m_font.m_scaledFont); + cairo_ft_scaled_font_unlock_face(fontData->platformData().m_scaledFont); return haveGlyphs; } diff --git a/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp b/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp index 8fada5c..8d0baa6 100644 --- a/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp +++ b/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp @@ -78,12 +78,12 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b if (bufferLength > GlyphPage::size) return false; - if (!fontData->m_font.m_font || fontData->m_font.m_font == reinterpret_cast<PangoFont*>(-1)) + if (!fontData->platformData().m_font || fontData->platformData().m_font == reinterpret_cast<PangoFont*>(-1)) return false; bool haveGlyphs = false; for (unsigned i = 0; i < length; i++) { - Glyph glyph = pango_font_get_glyph(fontData->m_font.m_font, fontData->m_font.m_context, buffer[i]); + Glyph glyph = pango_font_get_glyph(fontData->platformData().m_font, fontData->platformData().m_context, buffer[i]); if (!glyph) setGlyphDataForIndex(offset + i, 0, 0); else { diff --git a/WebCore/platform/graphics/gtk/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp index d8b38a0..e08c1ab 100644 --- a/WebCore/platform/graphics/gtk/IconGtk.cpp +++ b/WebCore/platform/graphics/gtk/IconGtk.cpp @@ -33,7 +33,6 @@ #include "CString.h" #include "GraphicsContext.h" #include "MIMETypeRegistry.h" -#include "NotImplemented.h" #include "PassRefPtr.h" #include <gtk/gtk.h> diff --git a/WebCore/platform/graphics/gtk/ImageGtk.cpp b/WebCore/platform/graphics/gtk/ImageGtk.cpp index b745209..0e92d6c 100644 --- a/WebCore/platform/graphics/gtk/ImageGtk.cpp +++ b/WebCore/platform/graphics/gtk/ImageGtk.cpp @@ -26,12 +26,52 @@ #include "config.h" #include "BitmapImage.h" +#include "CString.h" +#include "GOwnPtr.h" -// This function loads resources from WebKit -Vector<char> loadResourceIntoArray(const char*); +#include <cairo.h> +#include <gtk/gtk.h> + +namespace WTF { + +template <> void freeOwnedGPtr<GtkIconInfo>(GtkIconInfo* info) +{ + if (info) + gtk_icon_info_free(info); +} + +} namespace WebCore { +static CString getIconFileNameOrFallback(const char* name, const char* fallback) +{ + GOwnPtr<GtkIconInfo> info(gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(), + name, 16, GTK_ICON_LOOKUP_NO_SVG)); + if (!info) + return String::format("%s/webkit-1.0/images/%s.png", DATA_DIR, fallback).utf8(); + + return CString(gtk_icon_info_get_filename(info.get())); +} + +static PassRefPtr<SharedBuffer> loadResourceSharedBuffer(const char* name) +{ + CString fileName; + + // Find the path for the image + if (strcmp("missingImage", name) == 0) + fileName = getIconFileNameOrFallback(GTK_STOCK_MISSING_IMAGE, "missingImage"); + else + fileName = String::format("%s/webkit-1.0/images/%s.png", DATA_DIR, name).utf8(); + + GOwnPtr<gchar> content; + gsize length; + if (!g_file_get_contents(fileName.data(), &content.outPtr(), &length, 0)) + return SharedBuffer::create(); + + return SharedBuffer::create(content.get(), length); +} + void BitmapImage::initPlatformData() { } @@ -40,13 +80,34 @@ void BitmapImage::invalidatePlatformData() { } -PassRefPtr<Image> Image::loadPlatformResource(const char *name) +PassRefPtr<Image> Image::loadPlatformResource(const char* name) { - Vector<char> arr = loadResourceIntoArray(name); RefPtr<BitmapImage> img = BitmapImage::create(); - RefPtr<SharedBuffer> buffer = SharedBuffer::create(arr.data(), arr.size()); - img->setData(buffer, true); + RefPtr<SharedBuffer> buffer = loadResourceSharedBuffer(name); + img->setData(buffer.release(), true); return img.release(); } +GdkPixbuf* BitmapImage::getGdkPixbuf() +{ + int width = cairo_image_surface_get_width(frameAtIndex(currentFrame())); + int height = cairo_image_surface_get_height(frameAtIndex(currentFrame())); + + int bestDepth = gdk_visual_get_best_depth(); + GdkColormap* cmap = gdk_colormap_new(gdk_visual_get_best_with_depth(bestDepth), true); + + GdkPixmap* pixmap = gdk_pixmap_new(0, width, height, bestDepth); + gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap), cmap); + cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(pixmap)); + cairo_set_source_surface(cr, frameAtIndex(currentFrame()), 0, 0); + cairo_paint(cr); + cairo_destroy(cr); + + GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(0, GDK_DRAWABLE(pixmap), 0, 0, 0, 0, 0, width, height); + g_object_unref(pixmap); + g_object_unref(cmap); + + return pixbuf; +} + } diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp index 4203a3c..6684108 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp @@ -49,7 +49,7 @@ void SimpleFontData::platformInit() { cairo_font_extents_t font_extents; cairo_text_extents_t text_extents; - cairo_scaled_font_extents(m_font.m_scaledFont, &font_extents); + cairo_scaled_font_extents(m_platformData.m_scaledFont, &font_extents); m_ascent = static_cast<int>(font_extents.ascent); m_descent = static_cast<int>(font_extents.descent); m_lineSpacing = static_cast<int>(font_extents.height); @@ -60,11 +60,19 @@ void SimpleFontData::platformInit() // while we figure out what's going on. if (m_lineSpacing < m_ascent + m_descent) m_lineSpacing = m_ascent + m_descent; - cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents); + cairo_scaled_font_text_extents(m_platformData.m_scaledFont, "x", &text_extents); m_xHeight = text_extents.height; - cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents); + cairo_scaled_font_text_extents(m_platformData.m_scaledFont, " ", &text_extents); m_spaceWidth = static_cast<int>(text_extents.x_advance); m_lineGap = m_lineSpacing - m_ascent - m_descent; + m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; +} + +void SimpleFontData::platformCharWidthInit() +{ + m_avgCharWidth = 0.f; + m_maxCharWidth = 0.f; + initCharWidths(); } void SimpleFontData::platformDestroy() @@ -86,38 +94,38 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes bool SimpleFontData::containsCharacters(const UChar* characters, int length) const { - FT_Face face = cairo_ft_scaled_font_lock_face(m_font.m_scaledFont); + FT_Face face = cairo_ft_scaled_font_lock_face(m_platformData.m_scaledFont); if (!face) return false; for (unsigned i = 0; i < length; i++) { if (FcFreeTypeCharIndex(face, characters[i]) == 0) { - cairo_ft_scaled_font_unlock_face(m_font.m_scaledFont); + cairo_ft_scaled_font_unlock_face(m_platformData.m_scaledFont); return false; } } - cairo_ft_scaled_font_unlock_face(m_font.m_scaledFont); + cairo_ft_scaled_font_unlock_face(m_platformData.m_scaledFont); return true; } void SimpleFontData::determinePitch() { - m_treatAsFixedPitch = m_font.isFixedPitch(); + m_treatAsFixedPitch = m_platformData.isFixedPitch(); } float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { - ASSERT(m_font.m_scaledFont); + ASSERT(m_platformData.m_scaledFont); cairo_glyph_t cglyph = { glyph, 0, 0 }; cairo_text_extents_t extents; - cairo_scaled_font_glyph_extents(m_font.m_scaledFont, &cglyph, 1, &extents); + cairo_scaled_font_glyph_extents(m_platformData.m_scaledFont, &cglyph, 1, &extents); float w = (float)m_spaceWidth; - if (cairo_scaled_font_status(m_font.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) + if (cairo_scaled_font_status(m_platformData.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) w = (float)extents.x_advance; return w; } @@ -125,7 +133,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const void SimpleFontData::setFont(cairo_t* cr) const { ASSERT(cr); - m_font.setFont(cr); + m_platformData.setFont(cr); } } diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp index e345a8c..e57d9e6 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp @@ -48,7 +48,7 @@ void SimpleFontData::platformInit() { cairo_font_extents_t font_extents; cairo_text_extents_t text_extents; - cairo_scaled_font_extents(m_font.m_scaledFont, &font_extents); + cairo_scaled_font_extents(m_platformData.m_scaledFont, &font_extents); m_ascent = static_cast<int>(font_extents.ascent); m_descent = static_cast<int>(font_extents.descent); m_lineSpacing = static_cast<int>(font_extents.height); @@ -59,11 +59,19 @@ void SimpleFontData::platformInit() // while we figure out what's going on. if (m_lineSpacing < m_ascent + m_descent) m_lineSpacing = m_ascent + m_descent; - cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents); + cairo_scaled_font_text_extents(m_platformData.m_scaledFont, "x", &text_extents); m_xHeight = text_extents.height; - cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents); + cairo_scaled_font_text_extents(m_platformData.m_scaledFont, " ", &text_extents); m_spaceWidth = static_cast<int>(text_extents.x_advance); m_lineGap = m_lineSpacing - m_ascent - m_descent; + m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; +} + +void SimpleFontData::platformCharWidthInit() +{ + m_avgCharWidth = 0.f; + m_maxCharWidth = 0.f; + initCharWidths(); } void SimpleFontData::platformDestroy() @@ -87,7 +95,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con { bool result = true; - PangoCoverage* coverage = pango_font_get_coverage(m_font.m_font, pango_language_get_default()); + PangoCoverage* coverage = pango_font_get_coverage(m_platformData.m_font, pango_language_get_default()); for (int i = 0; i < length; i++) { if (PANGO_COVERAGE_NONE == pango_coverage_get(coverage, characters[i])) { @@ -108,19 +116,19 @@ void SimpleFontData::determinePitch() return; } - m_treatAsFixedPitch = m_font.isFixedPitch(); + m_treatAsFixedPitch = m_platformData.isFixedPitch(); } float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { - ASSERT(m_font.m_scaledFont); + ASSERT(m_platformData.m_scaledFont); cairo_glyph_t cglyph = { glyph, 0, 0 }; cairo_text_extents_t extents; - cairo_scaled_font_glyph_extents(m_font.m_scaledFont, &cglyph, 1, &extents); + cairo_scaled_font_glyph_extents(m_platformData.m_scaledFont, &cglyph, 1, &extents); float w = (float)m_spaceWidth; - if (cairo_scaled_font_status(m_font.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) + if (cairo_scaled_font_status(m_platformData.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) w = (float)extents.x_advance; return w; } @@ -128,7 +136,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const void SimpleFontData::setFont(cairo_t* cr) const { ASSERT(cr); - m_font.setFont(cr); + m_platformData.setFont(cr); } } 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; diff --git a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp index 16c3c00..895887f 100644 --- a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp +++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -161,11 +161,21 @@ struct nameTable { #pragma pack() -static void appendBigEndianStringToEOTHeader(Vector<uint8_t, 512>& eotHeader, const BigEndianUShort* string, unsigned short length) +EOTHeader::EOTHeader() { - size_t size = eotHeader.size(); - eotHeader.resize(size + length + 2 * sizeof(unsigned short)); - UChar* dst = reinterpret_cast<UChar*>(eotHeader.data() + size); + m_buffer.resize(sizeof(EOTPrefix)); +} + +void EOTHeader::updateEOTSize(size_t fontDataSize) +{ + prefix()->eotSize = m_buffer.size() + fontDataSize; +} + +void EOTHeader::appendBigEndianString(const BigEndianUShort* string, unsigned short length) +{ + size_t oldSize = m_buffer.size(); + m_buffer.resize(oldSize + length + 2 * sizeof(unsigned short)); + UChar* dst = reinterpret_cast<UChar*>(m_buffer.data() + oldSize); unsigned i = 0; dst[i++] = length; unsigned numCharacters = length / 2; @@ -174,7 +184,13 @@ static void appendBigEndianStringToEOTHeader(Vector<uint8_t, 512>& eotHeader, co dst[i] = 0; } -bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength) +void EOTHeader::appendPaddingShort() +{ + unsigned short padding = 0; + m_buffer.append(reinterpret_cast<uint8_t*>(&padding), sizeof(padding)); +} + +bool getEOTHeader(SharedBuffer* fontData, EOTHeader& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength) { overlayDst = 0; overlaySrc = 0; @@ -183,8 +199,7 @@ bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_ size_t dataLength = fontData->size(); const char* data = fontData->data(); - eotHeader.resize(sizeof(EOTPrefix)); - EOTPrefix* prefix = reinterpret_cast<EOTPrefix*>(eotHeader.data()); + EOTPrefix* prefix = eotHeader.prefix(); prefix->fontDataSize = dataLength; prefix->version = 0x00020001; @@ -306,9 +321,9 @@ bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_ prefix->reserved[3] = 0; prefix->padding1 = 0; - appendBigEndianStringToEOTHeader(eotHeader, familyName, familyNameLength); - appendBigEndianStringToEOTHeader(eotHeader, subfamilyName, subfamilyNameLength); - appendBigEndianStringToEOTHeader(eotHeader, versionString, versionStringLength); + eotHeader.appendBigEndianString(familyName, familyNameLength); + eotHeader.appendBigEndianString(subfamilyName, subfamilyNameLength); + eotHeader.appendBigEndianString(versionString, versionStringLength); // If possible, ensure that the family name is a prefix of the full name. if (fullNameLength >= familyNameLength && memcmp(familyName, fullName, familyNameLength)) { @@ -316,13 +331,10 @@ bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_ overlayDst = reinterpret_cast<const char*>(familyName) - data; overlayLength = familyNameLength; } + eotHeader.appendBigEndianString(fullName, fullNameLength); - appendBigEndianStringToEOTHeader(eotHeader, fullName, fullNameLength); - - unsigned short padding = 0; - eotHeader.append(reinterpret_cast<uint8_t*>(&padding), sizeof(padding)); - - prefix->eotSize = eotHeader.size() + fontData->size(); + eotHeader.appendPaddingShort(); + eotHeader.updateEOTSize(fontData->size()); return true; } diff --git a/WebCore/platform/graphics/opentype/OpenTypeUtilities.h b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h index a67ffc7..13dad6f 100644 --- a/WebCore/platform/graphics/opentype/OpenTypeUtilities.h +++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,9 +31,26 @@ namespace WebCore { +struct BigEndianUShort; +struct EOTPrefix; class SharedBuffer; -bool getEOTHeader(SharedBuffer* fontData, Vector<uint8_t, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength); +struct EOTHeader { + EOTHeader(); + + size_t size() const { return m_buffer.size(); } + const uint8_t* data() const { return m_buffer.data(); } + + EOTPrefix* prefix() { return reinterpret_cast<EOTPrefix*>(m_buffer.data()); } + void updateEOTSize(size_t); + void appendBigEndianString(const BigEndianUShort*, unsigned short length); + void appendPaddingShort(); + +private: + Vector<uint8_t, 512> m_buffer; +}; + +bool getEOTHeader(SharedBuffer* fontData, EOTHeader& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength); HANDLE renameAndActivateFont(SharedBuffer*, const String&); } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp index 114f073..668912e 100644 --- a/WebCore/platform/graphics/qt/FontCacheQt.cpp +++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp @@ -26,8 +26,11 @@ #include "FontDescription.h" #include "FontPlatformData.h" #include "Font.h" +#include "StringHash.h" #include <wtf/StdLibExtras.h> +#include <QHash> + namespace WebCore { FontCache* fontCache() @@ -44,9 +47,31 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne { } +typedef QHash<FontDescription, FontPlatformData*> FontPlatformDataCache; + +// using Q_GLOBAL_STATIC leads to crash. TODO investigate the way to fix this. +static FontPlatformDataCache* gFontPlatformDataCache; + +uint qHash(const FontDescription& key) +{ + uint value = CaseFoldingHash::hash(key.family().family()); + value ^= key.computedPixelSize(); + value ^= static_cast<int>(key.weight()); + return value; +} + FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString& family, bool checkingAlternateName) { - return new FontPlatformData(description); + if (!gFontPlatformDataCache) + gFontPlatformDataCache = new FontPlatformDataCache; + + FontPlatformData* fontData = gFontPlatformDataCache->value(description, 0); + if (!fontData) { + fontData = new FontPlatformData(description); + gFontPlatformDataCache->insert(description, fontData); + } + + return fontData; } SimpleFontData* FontCache::getCachedFontData(const FontPlatformData*) @@ -71,4 +96,12 @@ void FontCache::removeClient(FontSelector*) { } +void FontCache::invalidate() +{ + if (!gFontPlatformDataCache) + return; + + gFontPlatformDataCache->clear(); +} + } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp index 22ae205..50627b7 100644 --- a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp +++ b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp @@ -42,8 +42,6 @@ FontFallbackList::FontFallbackList() void FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector> fontSelector) { - releaseFontData(); - m_fontList.clear(); m_familyIndex = 0; m_pitch = UnknownPitch; m_loadingCustomFonts = false; @@ -53,6 +51,9 @@ void FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector> fontSel void FontFallbackList::releaseFontData() { + if (m_fontList.size()) + delete m_fontList[0].first; + m_fontList.clear(); } void FontFallbackList::determinePitch(const WebCore::Font* font) const @@ -90,7 +91,12 @@ const FontData* FontFallbackList::fontDataAt(const WebCore::Font* _font, unsigne family = family->next(); } - return new SimpleFontData(FontPlatformData(description), _font->wordSpacing(), _font->letterSpacing()); + if (m_fontList.size()) + return m_fontList[0].first; + + const FontData* result = new SimpleFontData(FontPlatformData(description), _font->wordSpacing(), _font->letterSpacing()); + m_fontList.append(pair<const FontData*, bool>(result, result->isCustomFont())); + return result; } const FontData* FontFallbackList::fontDataForCharacters(const WebCore::Font* font, const UChar*, int) const diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index 9ed5915..5a4b7b2 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -183,7 +183,7 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float p->drawText(pt, string, flags, run.padding()); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const { if (!run.length()) return 0; diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index ccf4b06..ed7ac47 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -99,7 +99,7 @@ static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op case CompositeHighlight: return QPainter::CompositionMode_SourceOver; case CompositePlusLighter: - return QPainter::CompositionMode_SourceOver; + return QPainter::CompositionMode_Plus; } return QPainter::CompositionMode_SourceOver; @@ -153,6 +153,18 @@ static Qt::PenStyle toQPenStyle(StrokeStyle style) return Qt::NoPen; } +static inline Qt::FillRule toQtFillRule(WindRule rule) +{ + switch(rule) { + case RULE_EVENODD: + return Qt::OddEvenFill; + case RULE_NONZERO: + return Qt::WindingFill; + } + qDebug("Qt: unrecognized wind rule!"); + return Qt::OddEvenFill; +} + struct TransparencyLayer { TransparencyLayer(const QPainter* p, const QRect &rect) @@ -563,7 +575,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp QPainter *p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); - p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); + p->setRenderHint(QPainter::Antialiasing, true); p->drawArc(rect, startAngle * 16, angleSpan * 16); @@ -606,6 +618,7 @@ void GraphicsContext::fillPath() QPainter *p = m_data->p(); QPainterPath path = m_data->currentPath; + path.setFillRule(toQtFillRule(fillRule())); switch (m_common->state.fillColorSpace) { case SolidColorSpace: @@ -634,6 +647,7 @@ void GraphicsContext::strokePath() QPainter *p = m_data->p(); QPen pen = p->pen(); QPainterPath path = m_data->currentPath; + path.setFillRule(toQtFillRule(fillRule())); switch (m_common->state.strokeColorSpace) { case SolidColorSpace: @@ -1097,7 +1111,13 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, rect.width() - (thickness * 2), rect.height() - (thickness * 2))); path.setFillRule(Qt::OddEvenFill); - m_data->p()->setClipPath(path, Qt::IntersectClip); + + QPainter *p = m_data->p(); + + const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); + p->setRenderHint(QPainter::Antialiasing, true); + p->setClipPath(path, Qt::IntersectClip); + p->setRenderHint(QPainter::Antialiasing, antiAlias); } void GraphicsContext::concatCTM(const TransformationMatrix& transform) diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp index b04668c..c9f3ced 100644 --- a/WebCore/platform/graphics/qt/IconQt.cpp +++ b/WebCore/platform/graphics/qt/IconQt.cpp @@ -24,7 +24,6 @@ #include "GraphicsContext.h" #include "PlatformString.h" #include "IntRect.h" -#include "NotImplemented.h" #include <qpainter.h> #include <qpixmap.h> diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp index d748305..506a8ea 100644 --- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -47,7 +47,24 @@ ImageBufferData::ImageBufferData(const IntSize& size) : m_pixmap(size) { m_pixmap.fill(QColor(Qt::transparent)); - m_painter.set(new QPainter(&m_pixmap)); + + QPainter* painter = new QPainter(&m_pixmap); + m_painter.set(painter); + + // Since ImageBuffer is used mainly for Canvas, explicitly initialize + // its painter's pen and brush with the corresponding canvas defaults + // NOTE: keep in sync with CanvasRenderingContext2D::State + QPen pen = painter->pen(); + pen.setColor(Qt::black); + pen.setWidth(1); + pen.setCapStyle(Qt::FlatCap); + pen.setJoinStyle(Qt::MiterJoin); + pen.setMiterLimit(10); + painter->setPen(pen); + QBrush brush = painter->brush(); + brush.setColor(Qt::black); + painter->setBrush(brush); + painter->setCompositionMode(QPainter::CompositionMode_SourceOver); } ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success) diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index 394c7a7..cd32428 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -197,7 +197,8 @@ ImageDecoderQt* ImageDecoderQt::create(const SharedBuffer& data) } ImageDecoderQt::ImageDecoderQt(const QString &imageFormat) - : m_imageFormat(imageFormat) + : m_hasAlphaChannel(false) + , m_imageFormat(imageFormat) { } @@ -212,6 +213,7 @@ bool ImageDecoderQt::hasFirstImageHeader() const void ImageDecoderQt::reset() { + m_hasAlphaChannel = false; m_failed = false; m_imageList.clear(); m_pixmapCache.clear(); @@ -230,6 +232,9 @@ void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived) const ReadContext::ReadResult readResult = readContext.read(allDataReceived); + if (hasFirstImageHeader()) + m_hasAlphaChannel = m_imageList[0].m_image.hasAlphaChannel(); + if (debugImageDecoderQt) qDebug() << " read returns " << readResult; @@ -280,7 +285,7 @@ int ImageDecoderQt::repetitionCount() const bool ImageDecoderQt::supportsAlpha() const { - return hasFirstImageHeader() && m_imageList[0].m_image.hasAlphaChannel(); + return m_hasAlphaChannel; } int ImageDecoderQt::duration(size_t index) const @@ -314,6 +319,10 @@ QPixmap* ImageDecoderQt::imageAtIndex(size_t index) const if (!m_pixmapCache.contains(index)) { m_pixmapCache.insert(index, QPixmap::fromImage(m_imageList[index].m_image)); + + // store null image since the converted pixmap is already in pixmap cache + Q_ASSERT(m_imageList[index].m_imageState == ImageComplete); + m_imageList[index].m_image = QImage(); } return &m_pixmapCache[index]; } diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h index a2eb6aa..b8c3edd 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.h +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h @@ -81,8 +81,9 @@ private: int m_duration; }; + bool m_hasAlphaChannel; typedef QList<ImageData> ImageList; - ImageList m_imageList; + mutable ImageList m_imageList; mutable QHash<int, QPixmap> m_pixmapCache; int m_loopCount; QString m_imageFormat; diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp index 3bc67ae..a2e96f3 100644 --- a/WebCore/platform/graphics/qt/ImageQt.cpp +++ b/WebCore/platform/graphics/qt/ImageQt.cpp @@ -31,12 +31,12 @@ #include "config.h" #include "Image.h" +#include "ImageObserver.h" #include "BitmapImage.h" #include "FloatRect.h" #include "PlatformString.h" #include "GraphicsContext.h" #include "TransformationMatrix.h" -#include "NotImplemented.h" #include "StillImageQt.h" #include "qwebsettings.h" @@ -117,6 +117,9 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const p->setBrushOrigin(phase); p->fillRect(destRect, b); ctxt->restore(); + + if (imageObserver()) + imageObserver()->didDraw(this); } void BitmapImage::initPlatformData() @@ -159,6 +162,9 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, painter->drawPixmap(dst, *image, src); ctxt->restore(); + + if (imageObserver()) + imageObserver()->didDraw(this); } void BitmapImage::checkForSolidColor() diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp index 84de443..621728e 100644 --- a/WebCore/platform/graphics/qt/ImageSourceQt.cpp +++ b/WebCore/platform/graphics/qt/ImageSourceQt.cpp @@ -29,7 +29,6 @@ #include "config.h" #include "ImageSource.h" #include "ImageDecoderQt.h" -#include "NotImplemented.h" #include "SharedBuffer.h" #include <QBuffer> diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp index a8a3ea2..7569031 100644 --- a/WebCore/platform/graphics/qt/PathQt.cpp +++ b/WebCore/platform/graphics/qt/PathQt.cpp @@ -39,6 +39,7 @@ #include <QPainterPath> #include <QTransform> #include <QString> +#include <wtf/OwnPtr.h> #define _USE_MATH_DEFINES #include <math.h> @@ -91,7 +92,7 @@ bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) // FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer // on each call. - std::auto_ptr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false); + OwnPtr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false); GraphicsContext* gc = scratchImage->context(); QPainterPathStroker stroke; applier->strokeStyle(gc); @@ -123,7 +124,7 @@ FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) { // FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer // on each call. - std::auto_ptr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false); + OwnPtr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false); GraphicsContext* gc = scratchImage->context(); QPainterPathStroker stroke; if (applier) { diff --git a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp index 6cf4e55..f823f84 100644 --- a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp +++ b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp @@ -30,7 +30,7 @@ namespace WebCore { void SimpleFontData::determinePitch() { - m_treatAsFixedPitch = m_font.font().fixedPitch(); + m_treatAsFixedPitch = m_platformData.font().fixedPitch(); } bool SimpleFontData::containsCharacters(const UChar*, int length) const @@ -40,7 +40,7 @@ bool SimpleFontData::containsCharacters(const UChar*, int length) const void SimpleFontData::platformInit() { - QFontMetrics fm(m_font.font()); + QFontMetrics fm(m_platformData.font()); m_ascent = fm.ascent(); m_descent = fm.descent(); @@ -59,6 +59,13 @@ void SimpleFontData::platformGlyphInit() m_missingGlyphData.glyph = 0; } +void SimpleFontData::platformCharWidthInit() +{ + QFontMetrics fm(m_platformData.font()); + m_avgCharWidth = fm.averageCharWidth(); + m_maxCharWidth = fm.maxWidth(); +} + void SimpleFontData::platformDestroy() { } diff --git a/WebCore/platform/graphics/skia/GradientSkia.cpp b/WebCore/platform/graphics/skia/GradientSkia.cpp index 2d2000c..ac7366c 100644 --- a/WebCore/platform/graphics/skia/GradientSkia.cpp +++ b/WebCore/platform/graphics/skia/GradientSkia.cpp @@ -60,12 +60,14 @@ static SkColor makeSkColor(float a, float r, float g, float b) // ends as necessary. static size_t totalStopsNeeded(const Gradient::ColorStop* stopData, size_t count) { + // N.B.: The tests in this function should kept in sync with the ones in + // fillStops(), or badness happens. const Gradient::ColorStop* stop = stopData; size_t countUsed = count; if (count < 1 || stop->stop > 0.0) countUsed++; stop += count - 1; - if (count < 2 || stop->stop < 1.0) + if (count < 1 || stop->stop < 1.0) countUsed++; return countUsed; } diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index 376fa4b..33ca23a 100644 --- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -449,10 +449,8 @@ void GraphicsContext::drawConvexPolygon(size_t numPoints, return; SkPaint paint; - if (fillColor().alpha() > 0) { - platformContext()->setupPaintForFilling(&paint); - platformContext()->canvas()->drawPath(path, paint); - } + platformContext()->setupPaintForFilling(&paint); + platformContext()->canvas()->drawPath(path, paint); if (strokeStyle() != NoStroke) { paint.reset(); @@ -472,10 +470,8 @@ void GraphicsContext::drawEllipse(const IntRect& elipseRect) return; SkPaint paint; - if (fillColor().alpha() > 0) { - platformContext()->setupPaintForFilling(&paint); - platformContext()->canvas()->drawOval(rect, paint); - } + platformContext()->setupPaintForFilling(&paint); + platformContext()->canvas()->drawOval(rect, paint); if (strokeStyle() != NoStroke) { paint.reset(); @@ -685,9 +681,6 @@ void GraphicsContext::fillPath() const GraphicsContextState& state = m_common->state; ColorSpace colorSpace = state.fillColorSpace; - if (colorSpace == SolidColorSpace && !fillColor().alpha()) - return; - path.setFillType(state.fillRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); @@ -718,9 +711,6 @@ void GraphicsContext::fillRect(const FloatRect& rect) const GraphicsContextState& state = m_common->state; ColorSpace colorSpace = state.fillColorSpace; - if (colorSpace == SolidColorSpace && !fillColor().alpha()) - return; - SkPaint paint; platformContext()->setupPaintForFilling(&paint); @@ -739,9 +729,6 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) if (paintingDisabled()) return; - if (!color.alpha()) - return; - SkRect r = rect; if (!isRectSkiaSafe(getCTM(), r)) { // Special case when the rectangle overflows fixed point. This is a @@ -907,8 +894,13 @@ void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) // FIXME: This is lifted directly off SkiaSupport, lines 49-74 // so it is not guaranteed to work correctly. size_t dashLength = dashes.size(); - if (!dashLength) + if (!dashLength) { + // If no dash is set, revert to solid stroke + // FIXME: do we need to set NoStroke in some cases? + platformContext()->setStrokeStyle(SolidStroke); + platformContext()->setDashPathEffect(0); return; + } size_t count = (dashLength % 2) == 0 ? dashLength : dashLength * 2; SkScalar* intervals = new SkScalar[count]; @@ -962,6 +954,12 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, if (paintingDisabled()) return; + // Detect when there's no effective shadow and clear the looper. + if (size.width() == 0 && size.height() == 0 && blurInt == 0) { + platformContext()->setDrawLooper(NULL); + return; + } + double width = size.width(); double height = size.height(); double blur = blurInt; @@ -1076,9 +1074,6 @@ void GraphicsContext::strokePath() const GraphicsContextState& state = m_common->state; ColorSpace colorSpace = state.strokeColorSpace; - if (colorSpace == SolidColorSpace && !strokeColor().alpha()) - return; - SkPaint paint; platformContext()->setupPaintForStroking(&paint, 0, 0); @@ -1103,9 +1098,6 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) const GraphicsContextState& state = m_common->state; ColorSpace colorSpace = state.strokeColorSpace; - if (colorSpace == SolidColorSpace && !strokeColor().alpha()) - return; - SkPaint paint; platformContext()->setupPaintForStroking(&paint, 0, 0); paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth)); diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index 5e90491..600882d 100644 --- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -36,7 +36,6 @@ #include "BitmapImageSingleFrameSkia.h" #include "GraphicsContext.h" #include "ImageData.h" -#include "NotImplemented.h" #include "PlatformContextSkia.h" #include "PNGImageEncoder.h" #include "SkiaUtils.h" diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index d7f2830..cb089bb 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -38,7 +38,6 @@ #include "GraphicsContext.h" #include "Logging.h" #include "NativeImageSkia.h" -#include "NotImplemented.h" #include "PlatformContextSkia.h" #include "PlatformString.h" #include "SkiaUtils.h" @@ -226,6 +225,12 @@ static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImag SkPaint paint; paint.setPorterDuffXfermode(compOp); paint.setFilterBitmap(true); + int alpha = roundf(platformContext->getAlpha() * 256); + if (alpha > 255) + alpha = 255; + else if (alpha < 0) + alpha = 0; + paint.setAlpha(alpha); skia::PlatformCanvas* canvas = platformContext->canvas(); @@ -305,7 +310,8 @@ void Image::drawPattern(GraphicsContext* context, CompositeOperator compositeOp, const FloatRect& destRect) { - if (destRect.isEmpty() || floatSrcRect.isEmpty()) + FloatRect normSrcRect = normalizeRect(floatSrcRect); + if (destRect.isEmpty() || normSrcRect.isEmpty()) return; // nothing to draw NativeImageSkia* bitmap = nativeImageForCurrentFrame(); @@ -316,7 +322,7 @@ void Image::drawPattern(GraphicsContext* context, // it will internally reference the old bitmap's pixels, adjusting the row // stride so the extra pixels appear as padding to the subsetted bitmap. SkBitmap srcSubset; - SkIRect srcRect = enclosingIntRect(floatSrcRect); + SkIRect srcRect = enclosingIntRect(normSrcRect); bitmap->extractSubset(&srcSubset, srcRect); SkBitmap resampled; @@ -363,9 +369,9 @@ void Image::drawPattern(GraphicsContext* context, // origin of the destination rect, which is what WebKit expects. Skia uses // the coordinate system origin as the base for the patter. If WebKit wants // a shifted image, it will shift it from there using the patternTransform. - float adjustedX = phase.x() + floatSrcRect.x() * + float adjustedX = phase.x() + normSrcRect.x() * narrowPrecisionToFloat(patternTransform.a()); - float adjustedY = phase.y() + floatSrcRect.y() * + float adjustedY = phase.y() + normSrcRect.y() * narrowPrecisionToFloat(patternTransform.d()); matrix.postTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY)); diff --git a/WebCore/platform/graphics/skia/PathSkia.cpp b/WebCore/platform/graphics/skia/PathSkia.cpp index 2700da8..9d9df52 100644 --- a/WebCore/platform/graphics/skia/PathSkia.cpp +++ b/WebCore/platform/graphics/skia/PathSkia.cpp @@ -81,9 +81,15 @@ void Path::translate(const FloatSize& size) FloatRect Path::boundingRect() const { + // FIXME: This #ifdef can go away once we're firmly using the new Skia. + // During the transition, this makes the code compatible with both versions. +#ifdef SK_USE_OLD_255_TO_256 + return m_path->getBounds(); +#else SkRect rect; m_path->computeBounds(&rect, SkPath::kExact_BoundsType); return rect; +#endif } void Path::moveTo(const FloatPoint& point) @@ -275,9 +281,15 @@ static FloatRect boundingBoxForCurrentStroke(const GraphicsContext* context) context->platformContext()->setupPaintForStroking(&paint, 0, 0); SkPath boundingPath; paint.getFillPath(context->platformContext()->currentPathInLocalCoordinates(), &boundingPath); + // FIXME: This #ifdef can go away once we're firmly using the new Skia. + // During the transition, this makes the code compatible with both versions. +#ifdef SK_USE_OLD_255_TO_256 + return boundingPath.getBounds(); +#else SkRect r; boundingPath.computeBounds(&r, SkPath::kExact_BoundsType); return r; +#endif } FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index 6c633f2..74b2bfe 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -277,13 +277,13 @@ void PlatformContextSkia::drawRect(SkRect rect) if (oldFillColor != m_state->m_strokeColor) setFillColor(m_state->m_strokeColor); setupPaintForFilling(&paint); - SkRect topBorder = { rect.fLeft, rect.fTop, rect.width(), 1 }; + SkRect topBorder = { rect.fLeft, rect.fTop, rect.fRight, rect.fTop + 1 }; canvas()->drawRect(topBorder, paint); - SkRect bottomBorder = { rect.fLeft, rect.fBottom - 1, rect.width(), 1 }; + SkRect bottomBorder = { rect.fLeft, rect.fBottom - 1, rect.fRight, rect.fBottom }; canvas()->drawRect(bottomBorder, paint); - SkRect leftBorder = { rect.fLeft, rect.fTop + 1, 1, rect.height() - 2 }; + SkRect leftBorder = { rect.fLeft, rect.fTop + 1, rect.fLeft + 1, rect.fBottom - 1 }; canvas()->drawRect(leftBorder, paint); - SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, 1, rect.height() - 2 }; + SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, rect.fRight, rect.fBottom - 1 }; canvas()->drawRect(rightBorder, paint); if (oldFillColor != m_state->m_strokeColor) setFillColor(oldFillColor); @@ -428,6 +428,11 @@ int PlatformContextSkia::getTextDrawingMode() const return m_state->m_textDrawingMode; } +float PlatformContextSkia::getAlpha() const +{ + return m_state->m_alpha; +} + void PlatformContextSkia::setTextDrawingMode(int mode) { // cTextClip is never used, so we assert that it isn't set: diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h index 8850a6a..25495aa 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.h +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -130,6 +130,7 @@ public: WebCore::StrokeStyle getStrokeStyle() const; float getStrokeThickness() const; int getTextDrawingMode() const; + float getAlpha() const; void beginPath(); void addPath(const SkPath&); diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/WebCore/platform/graphics/skia/SkiaFontWin.cpp index d0cd4c5..7f12508 100644 --- a/WebCore/platform/graphics/skia/SkiaFontWin.cpp +++ b/WebCore/platform/graphics/skia/SkiaFontWin.cpp @@ -220,6 +220,16 @@ void SkiaWinOutlineCache::removePathsForFont(HFONT hfont) deleteOutline(outlineCache.find(*i)); } +bool windowsCanHandleDrawTextShadow(WebCore::GraphicsContext *context) +{ + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + + bool hasShadow = context->getShadow(shadowSize, shadowBlur, shadowColor); + return (hasShadow && (shadowBlur == 0) && (shadowColor.alpha() == 255) && (context->fillColor().alpha() == 255)); +} + bool windowsCanHandleTextDrawing(GraphicsContext* context) { // Check for non-translation transforms. Sometimes zooms will look better in @@ -244,7 +254,7 @@ bool windowsCanHandleTextDrawing(GraphicsContext* context) return false; // Check for shadow effects. - if (context->platformContext()->getDrawLooper()) + if (context->platformContext()->getDrawLooper() && (!windowsCanHandleDrawTextShadow(context))) return false; return true; diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.h b/WebCore/platform/graphics/skia/SkiaFontWin.h index 0e0c953..0bad30f 100644 --- a/WebCore/platform/graphics/skia/SkiaFontWin.h +++ b/WebCore/platform/graphics/skia/SkiaFontWin.h @@ -68,8 +68,12 @@ private: // Remember that Skia's text drawing origin is the baseline, like WebKit, not // the top, like Windows. +// Returns true if the fillColor and shadowColor are opaque and the text-shadow +// is not blurred. +bool windowsCanHandleDrawTextShadow(GraphicsContext*); + // Returns true if advanced font rendering is recommended. -bool windowsCanHandleTextDrawing(GraphicsContext* context); +bool windowsCanHandleTextDrawing(GraphicsContext*); // Note that the offsets parameter is optional. If not NULL it represents a // per glyph offset (such as returned by ScriptPlace Windows API function). diff --git a/WebCore/platform/graphics/skia/SkiaUtils.cpp b/WebCore/platform/graphics/skia/SkiaUtils.cpp index 55cba37..4242e7d 100644 --- a/WebCore/platform/graphics/skia/SkiaUtils.cpp +++ b/WebCore/platform/graphics/skia/SkiaUtils.cpp @@ -47,7 +47,7 @@ static const struct CompositOpToPorterDuffMode { uint8_t mPorterDuffMode; } gMapCompositOpsToPorterDuffModes[] = { { CompositeClear, SkPorterDuff::kClear_Mode }, - { CompositeCopy, SkPorterDuff::kSrcOver_Mode }, // TODO + { CompositeCopy, SkPorterDuff::kSrc_Mode }, { CompositeSourceOver, SkPorterDuff::kSrcOver_Mode }, { CompositeSourceIn, SkPorterDuff::kSrcIn_Mode }, { CompositeSourceOut, SkPorterDuff::kSrcOut_Mode }, @@ -59,7 +59,7 @@ static const struct CompositOpToPorterDuffMode { { CompositeXOR, SkPorterDuff::kXor_Mode }, { CompositePlusDarker, SkPorterDuff::kDarken_Mode }, { CompositeHighlight, SkPorterDuff::kSrcOver_Mode }, // TODO - { CompositePlusLighter, SkPorterDuff::kLighten_Mode } + { CompositePlusLighter, SkPorterDuff::kAdd_Mode } }; SkPorterDuff::Mode WebCoreCompositeToSkiaComposite(CompositeOperator op) @@ -135,12 +135,7 @@ bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath:: int scale = 1; SkRect bounds; -#if PLATFORM(SGL) - // this is the API from skia/trunk bounds = originalPath->getBounds(); -#else - originalPath->computeBounds(&bounds, SkPath::kFast_BoundsType); -#endif // We can immediately return false if the point is outside the bounding rect if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()))) diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.cpp b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp index 63a7b8e..a358aaf 100644 --- a/WebCore/platform/graphics/transforms/TransformationMatrix.cpp +++ b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp @@ -31,6 +31,7 @@ #include "FloatQuad.h" #include "IntRect.h" +#include <wtf/Assertions.h> #include <wtf/MathExtras.h> namespace WebCore { @@ -556,6 +557,9 @@ FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q) const FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const { + if (isIdentityOrTranslation()) + return FloatPoint(p.x() + static_cast<float>(m_matrix[3][0]), p.y() + static_cast<float>(m_matrix[3][1])); + double x, y; multVecMatrix(p.x(), p.y(), x, y); return FloatPoint(static_cast<float>(x), static_cast<float>(y)); @@ -563,20 +567,16 @@ FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const { + if (isIdentityOrTranslation()) + return FloatPoint3D(p.x() + static_cast<float>(m_matrix[3][0]), + p.y() + static_cast<float>(m_matrix[3][1]), + p.z() + static_cast<float>(m_matrix[3][2])); + double x, y, z; multVecMatrix(p.x(), p.y(), p.z(), x, y, z); return FloatPoint3D(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)); } -IntPoint TransformationMatrix::mapPoint(const IntPoint& point) const -{ - double x, y; - multVecMatrix(point.x(), point.y(), x, y); - - // Round the point. - return IntPoint(lround(x), lround(y)); -} - IntRect TransformationMatrix::mapRect(const IntRect &rect) const { return enclosingIntRect(mapRect(FloatRect(rect))); @@ -584,12 +584,24 @@ IntRect TransformationMatrix::mapRect(const IntRect &rect) const FloatRect TransformationMatrix::mapRect(const FloatRect& r) const { + if (isIdentityOrTranslation()) { + FloatRect mappedRect(r); + mappedRect.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1])); + return mappedRect; + } + FloatQuad resultQuad = mapQuad(FloatQuad(r)); return resultQuad.boundingBox(); } FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const { + if (isIdentityOrTranslation()) { + FloatQuad mappedQuad(q); + mappedQuad.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1])); + return mappedQuad; + } + FloatQuad result; result.setP1(mapPoint(q.p1())); result.setP2(mapPoint(q.p2())); @@ -781,38 +793,19 @@ TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, doubl TransformationMatrix& TransformationMatrix::translate(double tx, double ty) { -#ifdef ANDROID_FASTER_MATRIX m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0]; m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1]; m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2]; m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3]; -#else - // FIXME: optimize to avoid matrix copy - TransformationMatrix mat; - mat.m_matrix[3][0] = tx; - mat.m_matrix[3][1] = ty; - - multLeft(mat); -#endif return *this; } TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz) { -#ifdef ANDROID_FASTER_MATRIX m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0] + tz * m_matrix[2][0]; m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1] + tz * m_matrix[2][1]; m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2] + tz * m_matrix[2][2]; m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3] + tz * m_matrix[2][3]; -#else - // FIXME: optimize to avoid matrix copy - TransformationMatrix mat; - mat.m_matrix[3][0] = tx; - mat.m_matrix[3][1] = ty; - mat.m_matrix[3][2] = tz; - - multLeft(mat); -#endif return *this; } @@ -945,6 +938,9 @@ void TransformationMatrix::multVecMatrix(double x, double y, double z, double& r bool TransformationMatrix::isInvertible() const { + if (isIdentityOrTranslation()) + return true; + double det = WebCore::determinant4x4(m_matrix); if (fabs(det) < SMALL_NUMBER) @@ -955,8 +951,19 @@ bool TransformationMatrix::isInvertible() const TransformationMatrix TransformationMatrix::inverse() const { - TransformationMatrix invMat; + if (isIdentityOrTranslation()) { + // identity matrix + if (m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0) + return TransformationMatrix(); + + // translation + return TransformationMatrix(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + -m_matrix[3][0], -m_matrix[3][1], -m_matrix[3][2], 1); + } + TransformationMatrix invMat; bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix); if (!inverted) return TransformationMatrix(); diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h index 62e4eb8..7b93e04 100644 --- a/WebCore/platform/graphics/transforms/TransformationMatrix.h +++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h @@ -26,6 +26,10 @@ #ifndef TransformationMatrix_h #define TransformationMatrix_h +#include "FloatPoint.h" +#include "IntPoint.h" +#include <string.h> //for memcpy + #if PLATFORM(CG) #include <CoreGraphics/CGAffineTransform.h> #elif PLATFORM(CAIRO) @@ -38,13 +42,9 @@ #include <wx/graphics.h> #endif -#include <string.h> //for memcpy - namespace WebCore { -class IntPoint; class IntRect; -class FloatPoint; class FloatPoint3D; class FloatRect; class FloatQuad; @@ -114,7 +114,10 @@ public: FloatPoint mapPoint(const FloatPoint&) const; // Like the version above, except that it rounds the mapped point to the nearest integer value. - IntPoint mapPoint(const IntPoint&) const; + IntPoint mapPoint(const IntPoint& p) const + { + return roundedIntPoint(mapPoint(FloatPoint(p))); + } // If the matrix has 3D components, the z component of the result is // dropped, effectively projecting the rect into the z=0 plane @@ -313,6 +316,14 @@ private: memcpy(m_matrix, m, sizeof(Matrix4)); } + bool isIdentityOrTranslation() const + { + return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 && + m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 && + m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 && + m_matrix[3][3] == 1; + } + Matrix4 m_matrix; }; diff --git a/WebCore/platform/graphics/win/ColorSafari.cpp b/WebCore/platform/graphics/win/ColorSafari.cpp index a04fd81..25b6b89 100644 --- a/WebCore/platform/graphics/win/ColorSafari.cpp +++ b/WebCore/platform/graphics/win/ColorSafari.cpp @@ -29,7 +29,6 @@ #include "config.h" #include "Color.h" -#include "NotImplemented.h" #include <CoreGraphics/CGColor.h> #include <SafariTheme/SafariTheme.h> #include <wtf/Assertions.h> diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp index feeb2ae..803f5db 100644 --- a/WebCore/platform/graphics/win/FontCGWin.cpp +++ b/WebCore/platform/graphics/win/FontCGWin.cpp @@ -181,7 +181,7 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData SetWorldTransform(hdc, &xform); } - SelectObject(hdc, font->m_font.hfont()); + SelectObject(hdc, font->platformData().hfont()); // Set the correct color. if (drawIntoBitmap) @@ -215,9 +215,9 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData xform.eDy = point.y(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); - if (font->m_syntheticBoldOffset) { + if (font->syntheticBoldOffset()) { xform.eM21 = 0; - xform.eDx = font->m_syntheticBoldOffset; + xform.eDx = font->syntheticBoldOffset(); xform.eDy = 0; ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); @@ -250,21 +250,21 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData if (drawingMode & cTextFill) { CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); - if (font->m_syntheticBoldOffset) { - CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0); + if (font->syntheticBoldOffset()) { + CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); - CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0); + CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } if (drawingMode & cTextStroke) { CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); - if (font->m_syntheticBoldOffset) { - CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0); + if (font->syntheticBoldOffset()) { + CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); - CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0); + CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } @@ -341,8 +341,8 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo graphicsContext->setFillColor(shadowFillColor); CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width(), point.y() + translation.height() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); - if (font->m_syntheticBoldOffset) { - CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width() + font->m_syntheticBoldOffset, point.y() + translation.height() + shadowSize.height()); + if (font->syntheticBoldOffset()) { + CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } graphicsContext->setFillColor(fillColor); @@ -350,8 +350,8 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); - if (font->m_syntheticBoldOffset) { - CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->m_syntheticBoldOffset, point.y() + translation.height()); + if (font->syntheticBoldOffset()) { + CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->syntheticBoldOffset(), point.y() + translation.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp index 1ac3359..24db173 100644 --- a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp @@ -116,7 +116,7 @@ size_t getBytesWithOffset(void *info, void* buffer, size_t offset, size_t count) // Streams the concatenation of a header and font data. class EOTStream { public: - EOTStream(const Vector<uint8_t, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength) + EOTStream(const EOTHeader& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength) : m_eotHeader(eotHeader) , m_fontData(fontData) , m_overlayDst(overlayDst) @@ -130,7 +130,7 @@ public: size_t read(void* buffer, size_t count); private: - const Vector<uint8_t, 512>& m_eotHeader; + const EOTHeader& m_eotHeader; const SharedBuffer* m_fontData; size_t m_overlayDst; size_t m_overlaySrc; @@ -206,7 +206,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, so we need to create an EOT header // and prepend it to the font data. - Vector<uint8_t, 512> eotHeader; + EOTHeader eotHeader; size_t overlayDst; size_t overlaySrc; size_t overlayLength; diff --git a/WebCore/platform/graphics/win/FontWin.cpp b/WebCore/platform/graphics/win/FontWin.cpp index 5e423e0..27d8dee 100644 --- a/WebCore/platform/graphics/win/FontWin.cpp +++ b/WebCore/platform/graphics/win/FontWin.cpp @@ -30,13 +30,17 @@ #include "GlyphBuffer.h" #include "GraphicsContext.h" #include "IntRect.h" -#include "NotImplemented.h" #include "SimpleFontData.h" #include "UniscribeController.h" #include <wtf/MathExtras.h> namespace WebCore { +bool Font::canReturnFallbackFontsForComplexText() +{ + return true; +} + FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const { @@ -85,9 +89,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 { - UniscribeController controller(this, run); + UniscribeController controller(this, run, fallbackFonts); controller.advance(run.length()); return controller.runWidthSoFar(); } diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp index da5b503..917631b 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -27,7 +27,6 @@ #include "GraphicsContext.h" #include "TransformationMatrix.h" -#include "NotImplemented.h" #include "Path.h" #include <CoreGraphics/CGBitmapContext.h> diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp index 1980d18..ca3cb5d 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp @@ -27,7 +27,6 @@ #include "GraphicsContext.h" #include "TransformationMatrix.h" -#include "NotImplemented.h" #include "Path.h" #include <cairo-win32.h> @@ -37,13 +36,61 @@ using namespace std; namespace WebCore { +static cairo_t* createCairoContextWithHDC(HDC hdc, bool hasAlpha) +{ + // Put the HDC In advanced mode so it will honor affine transforms. + SetGraphicsMode(hdc, GM_ADVANCED); + + HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + + BITMAP info; + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + + cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)info.bmBits, + CAIRO_FORMAT_ARGB32, + info.bmWidth, + info.bmHeight, + info.bmWidthBytes); + + cairo_t* context = cairo_create(image); + cairo_surface_destroy(image); + + return context; +} + +static BITMAPINFO bitmapInfoForSize(const IntSize& size) +{ + BITMAPINFO bitmapInfo; + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = size.width(); + bitmapInfo.bmiHeader.biHeight = size.height(); + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = 0; + bitmapInfo.bmiHeader.biXPelsPerMeter = 0; + bitmapInfo.bmiHeader.biYPelsPerMeter = 0; + bitmapInfo.bmiHeader.biClrUsed = 0; + bitmapInfo.bmiHeader.biClrImportant = 0; + + return bitmapInfo; +} + +static void fillWithClearColor(HBITMAP bitmap) +{ + BITMAP bmpInfo; + GetObject(bitmap, sizeof(bmpInfo), &bmpInfo); + int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + memset(bmpInfo.bmBits, 0, bufferSize); +} + GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha) : m_common(createGraphicsContextPrivate()) , m_data(new GraphicsContextPlatformPrivate) { if (dc) { - cairo_surface_t* surface = cairo_win32_surface_create(dc); - m_data->cr = cairo_create(surface); + m_data->cr = createCairoContextWithHDC(dc, hasAlpha); m_data->m_hdc = dc; } else { setPaintingDisabled(true); @@ -60,52 +107,95 @@ GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha) HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { - // FIXME: We aren't really doing anything with the 'mayCreateBitmap' flag. This needs - // to be addressed. - if (dstRect.isEmpty()) - return 0; - - // This is probably wrong, and definitely out of date. Pulled from old SVN - cairo_surface_t* surface = cairo_get_target(platformContext()); - HDC hdc = cairo_win32_surface_get_dc(surface); - SaveDC(hdc); - - // FIXME: We need to make sure a clip is really set on the HDC. - // Call SetWorldTransform to honor the current Cairo transform. - SetGraphicsMode(hdc, GM_ADVANCED); // We need this call for themes to honor world transforms. - cairo_matrix_t mat; - cairo_get_matrix(platformContext(), &mat); - XFORM xform; - xform.eM11 = mat.xx; - xform.eM12 = mat.xy; - xform.eM21 = mat.yx; - xform.eM22 = mat.yy; - xform.eDx = mat.x0; - xform.eDy = mat.y0; - ::SetWorldTransform(hdc, &xform); - - return hdc; + // FIXME: Should a bitmap be created also when a shadow is set? + if (mayCreateBitmap && inTransparencyLayer()) { + if (dstRect.isEmpty()) + return 0; + + // Create a bitmap DC in which to draw. + BITMAPINFO bitmapInfo = bitmapInfoForSize(dstRect.size()); + + void* pixels = 0; + HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0); + if (!bitmap) + return 0; + + HDC bitmapDC = ::CreateCompatibleDC(m_data->m_hdc); + ::SelectObject(bitmapDC, bitmap); + + // Fill our buffer with clear if we're going to alpha blend. + if (supportAlphaBlend) + fillWithClearColor(bitmap); + + // Make sure we can do world transforms. + SetGraphicsMode(bitmapDC, GM_ADVANCED); + + // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap. + XFORM xform; + xform.eM11 = 1.0f; + xform.eM12 = 0.0f; + xform.eM21 = 0.0f; + xform.eM22 = 1.0f; + xform.eDx = -dstRect.x(); + xform.eDy = -dstRect.y(); + ::SetWorldTransform(bitmapDC, &xform); + + return bitmapDC; + } + + cairo_surface_t* surface = cairo_win32_surface_create(m_data->m_hdc); + cairo_surface_flush(surface); + cairo_surface_destroy(surface); + + m_data->save(); + + return m_data->m_hdc; } void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { - // FIXME: We aren't really doing anything with the 'mayCreateBitmap' flag. This needs - // to be addressed. - if (dstRect.isEmpty()) - return; + if (!mayCreateBitmap || !hdc || !inTransparencyLayer()) { + m_data->restore(); + return; + } - cairo_surface_t* surface = cairo_get_target(platformContext()); - HDC hdc2 = cairo_win32_surface_get_dc(surface); - RestoreDC(hdc2, -1); - cairo_surface_mark_dirty(surface); + if (dstRect.isEmpty()) + return; + + HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + + BITMAP info; + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + + // Need to make a cairo_surface_t out of the bitmap's pixel buffer and then draw + // it into our context. + cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)info.bmBits, + CAIRO_FORMAT_ARGB32, + info.bmWidth, + info.bmHeight, + info.bmWidthBytes); + + // Scale the target surface to the new image size, and flip it + // so that when we set the srcImage as the surface it will draw + // right-side-up. + cairo_translate(m_data->cr, 0, dstRect.height()); + cairo_scale(m_data->cr, dstRect.width(), -dstRect.height()); + cairo_set_source_surface (m_data->cr, image, dstRect.x(), dstRect.y()); + + if (m_data->layers.size()) + cairo_paint_with_alpha(m_data->cr, m_data->layers.last()); + else + cairo_paint(m_data->cr); + + // Delete all our junk. + cairo_surface_destroy(image); + ::DeleteDC(hdc); + ::DeleteObject(bitmap); } void GraphicsContextPlatformPrivate::concatCTM(const TransformationMatrix& transform) { - cairo_surface_t* surface = cairo_get_target(cr); - HDC hdc = cairo_win32_surface_get_dc(surface); - SaveDC(hdc); - const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform); XFORM xform; @@ -116,7 +206,15 @@ void GraphicsContextPlatformPrivate::concatCTM(const TransformationMatrix& trans xform.eDx = matrix->x0; xform.eDy = matrix->y0; - ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); + ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY); +} + +void GraphicsContextPlatformPrivate::syncContext(PlatformGraphicsContext* cr) +{ + cairo_surface_t* surface = cairo_get_target(cr); + m_hdc = cairo_win32_surface_get_dc(surface); + + SetGraphicsMode(m_hdc, GM_ADVANCED); // We need this call for themes to honor world transforms. } } diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp index 95bb7bc..06428b8 100644 --- a/WebCore/platform/graphics/win/ImageCairoWin.cpp +++ b/WebCore/platform/graphics/win/ImageCairoWin.cpp @@ -47,13 +47,17 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) memset(bmpInfo.bmBits, 255, bufferSize); } - HDC tempDC = CreateCompatibleDC(0); - if (!tempDC) { - LOG_ERROR("Failed to create in-memory DC for Image::blit()"); - return false; - } - SelectObject(tempDC, bmp); - GraphicsContext gc(tempDC); + cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)bmpInfo.bmBits, + CAIRO_FORMAT_ARGB32, + bmpInfo.bmWidth, + bmpInfo.bmHeight, + bmpInfo.bmWidthBytes); + + + cairo_t* targetRef = cairo_create(image); + cairo_surface_destroy(image); + + GraphicsContext gc(targetRef); IntSize imageSize = BitmapImage::size(); if (size) @@ -62,7 +66,7 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy); // Do cleanup - DeleteDC(tempDC); + cairo_destroy(targetRef); return true; } diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index c293f49..35ea786 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -70,6 +70,8 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) , m_enabledTrackCount(0) + , m_totalTrackCount(0) + , m_hasUnsupportedTracks(false) , m_startedPlaying(false) , m_isStreaming(false) #if DRAW_FRAME_RATE @@ -320,9 +322,17 @@ void MediaPlayerPrivate::updateStates() long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError; - if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata && !m_player->inMediaDocument()) { - m_qtMovie->disableUnsupportedTracks(m_enabledTrackCount); - if (!m_enabledTrackCount) + if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) { + m_qtMovie->disableUnsupportedTracks(m_enabledTrackCount, m_totalTrackCount); + 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, eg. QuickTime VR, a movie with a sprite track, etc. Tell the + // MediaPlayerClient that we won't support it. + sawUnsupportedTracks(); + return; + } + } else if (!m_enabledTrackCount) loadState = QTMovieLoadStateError; } @@ -341,6 +351,14 @@ void MediaPlayerPrivate::updateStates() m_networkState = MediaPlayer::Loading; m_readyState = MediaPlayer::HaveNothing; } else { + if (m_player->inMediaDocument()) { + // Something went wrong in the loading of media within a standalone file. + // This can occur with chained ref movies that eventually resolve to a + // file we don't support. + sawUnsupportedTracks(); + return; + } + float loaded = maxTimeLoaded(); if (!loaded) m_readyState = MediaPlayer::HaveNothing; @@ -365,9 +383,18 @@ void MediaPlayerPrivate::updateStates() m_player->readyStateChanged(); } +void MediaPlayerPrivate::sawUnsupportedTracks() +{ + m_qtMovie->setDisabled(true); + m_hasUnsupportedTracks = true; + m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player); +} void MediaPlayerPrivate::didEnd() { + if (m_hasUnsupportedTracks) + return; + m_startedPlaying = false; #if DRAW_FRAME_RATE m_timeStoppedPlaying = GetTickCount(); @@ -378,20 +405,21 @@ void MediaPlayerPrivate::didEnd() void MediaPlayerPrivate::setSize(const IntSize& size) { - if (m_qtMovie) - m_qtMovie->setSize(size.width(), size.height()); + if (m_hasUnsupportedTracks || !m_qtMovie) + return; + m_qtMovie->setSize(size.width(), size.height()); } void MediaPlayerPrivate::setVisible(bool b) { - if (!m_qtMovie) + if (m_hasUnsupportedTracks || !m_qtMovie) return; m_qtMovie->setVisible(b); } void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r) { - if (p->paintingDisabled() || !m_qtMovie) + if (p->paintingDisabled() || !m_qtMovie || m_hasUnsupportedTracks) return; HDC hdc = p->getWindowsContext(r); m_qtMovie->paint(hdc, r.x(), r.y()); @@ -463,18 +491,27 @@ MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, c void MediaPlayerPrivate::movieEnded(QTMovieWin* movie) { + if (m_hasUnsupportedTracks) + return; + ASSERT(m_qtMovie.get() == movie); didEnd(); } void MediaPlayerPrivate::movieLoadStateChanged(QTMovieWin* movie) { + if (m_hasUnsupportedTracks) + return; + ASSERT(m_qtMovie.get() == movie); updateStates(); } void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie) { + if (m_hasUnsupportedTracks) + return; + ASSERT(m_qtMovie.get() == movie); updateStates(); m_player->timeChanged(); @@ -482,6 +519,9 @@ void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie) void MediaPlayerPrivate::movieNewImageAvailable(QTMovieWin* movie) { + if (m_hasUnsupportedTracks) + return; + ASSERT(m_qtMovie.get() == movie); #if DRAW_FRAME_RATE if (m_startedPlaying) { diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h index 63aa62b..3207867 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h @@ -98,6 +98,7 @@ private: void cancelSeek(); void seekTimerFired(Timer<MediaPlayerPrivate>*); float maxTimeLoaded() const; + void sawUnsupportedTracks(); virtual void movieEnded(QTMovieWin*); virtual void movieLoadStateChanged(QTMovieWin*); @@ -118,6 +119,8 @@ private: MediaPlayer::NetworkState m_networkState; MediaPlayer::ReadyState m_readyState; unsigned m_enabledTrackCount; + unsigned m_totalTrackCount; + bool m_hasUnsupportedTracks; bool m_startedPlaying; bool m_isStreaming; #if DRAW_FRAME_RATE diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp index 3f23698..1d10006 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.cpp +++ b/WebCore/platform/graphics/win/QTMovieWin.cpp @@ -91,6 +91,7 @@ public: void createGWorld(); void deleteGWorld(); void clearGWorld(); + void cacheMovieScale(); void setSize(int, int); @@ -112,6 +113,11 @@ public: int m_gWorldHeight; GWorldPtr m_savedGWorld; long m_loadError; + float m_widthScaleFactor; + float m_heightScaleFactor; +#if !ASSERT_DISABLED + bool m_scaleCached; +#endif }; QTMovieWinPrivate::QTMovieWinPrivate() @@ -133,6 +139,11 @@ QTMovieWinPrivate::QTMovieWinPrivate() , m_gWorldHeight(0) , m_savedGWorld(0) , m_loadError(0) + , m_widthScaleFactor(1) + , m_heightScaleFactor(1) +#if !ASSERT_DISABLED + , m_scaleCached(false) +#endif { } @@ -179,6 +190,26 @@ void QTMovieWinPrivate::endTask() updateTaskTimer(); } +void QTMovieWinPrivate::cacheMovieScale() +{ + Rect naturalRect; + Rect initialRect; + + GetMovieNaturalBoundsRect(m_movie, &naturalRect); + GetMovieBox(m_movie, &initialRect); + + int naturalWidth = naturalRect.right - naturalRect.left; + int naturalHeight = naturalRect.bottom - naturalRect.top; + + if (naturalWidth) + m_widthScaleFactor = (initialRect.right - initialRect.left) / naturalWidth; + if (naturalHeight) + m_heightScaleFactor = (initialRect.bottom - initialRect.top) / naturalHeight; +#if !ASSERT_DISABLED + m_scaleCached = true;; +#endif +} + void QTMovieWinPrivate::task() { ASSERT(m_tasking); @@ -192,20 +223,27 @@ void QTMovieWinPrivate::task() // GetMovieLoadState documentation says that you should not call it more often than every quarter of a second. if (systemTime() >= m_lastLoadStateCheckTime + 0.25 || m_loadError) { - // If load fails QT's load state is kMovieLoadStateComplete. + // If load fails QT's load state is QTMovieLoadStateComplete. // This is different from QTKit API and seems strange. - long loadState = m_loadError ? kMovieLoadStateError : GetMovieLoadState(m_movie); + long loadState = m_loadError ? QTMovieLoadStateError : GetMovieLoadState(m_movie); if (loadState != m_loadState) { // we only need to erase the movie gworld when the load state changes to loaded while it // is visible as the gworld is destroyed/created when visibility changes - if (loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded && m_visible) - clearGWorld(); + if (loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded) { + if (m_visible) + clearGWorld(); + cacheMovieScale(); + } m_loadState = loadState; - if (!m_movieController && m_loadState >= kMovieLoadStateLoaded) + if (!m_movieController && m_loadState >= QTMovieLoadStateLoaded) createMovieController(); m_client->movieLoadStateChanged(m_movieWin); + if (m_movieWin->m_disabled) { + endTask(); + return; + } } m_lastLoadStateCheckTime = systemTime(); } @@ -259,7 +297,7 @@ void QTMovieWinPrivate::registerDrawingCallback() void QTMovieWinPrivate::drawingComplete() { - if (!m_gWorld || m_loadState < kMovieLoadStateLoaded) + if (!m_gWorld || m_movieWin->m_disabled || m_loadState < QTMovieLoadStateLoaded) return; m_client->movieNewImageAvailable(m_movieWin); } @@ -284,7 +322,7 @@ void QTMovieWinPrivate::updateGWorld() void QTMovieWinPrivate::createGWorld() { ASSERT(!m_gWorld); - if (!m_movie) + if (!m_movie || m_loadState < QTMovieLoadStateLoaded) return; m_gWorldWidth = max(cGWorldMinWidth, m_width); @@ -334,8 +372,17 @@ void QTMovieWinPrivate::setSize(int width, int height) return; m_width = width; m_height = height; - if (!m_movie) + + // Do not change movie box before reaching load state loaded as we grab + // the initial size when task() sees that state for the first time, and + // we need the initial size to be able to scale movie properly. + if (!m_movie || m_loadState < QTMovieLoadStateLoaded) return; + +#if !ASSERT_DISABLED + ASSERT(m_scaleCached); +#endif + Rect bounds; bounds.top = 0; bounds.left = 0; @@ -364,6 +411,7 @@ void QTMovieWinPrivate::deleteGWorld() QTMovieWin::QTMovieWin(QTMovieWinClient* client) : m_private(new QTMovieWinPrivate()) + , m_disabled(false) { m_private->m_movieWin = this; m_private->m_client = client; @@ -478,8 +526,8 @@ void QTMovieWin::getNaturalSize(int& width, int& height) if (m_private->m_movie) GetMovieNaturalBoundsRect(m_private->m_movie, &rect); - width = rect.right; - height = rect.bottom; + width = (rect.right - rect.left) * m_private->m_widthScaleFactor; + height = (rect.bottom - rect.top) * m_private->m_heightScaleFactor; } void QTMovieWin::setSize(int width, int height) @@ -593,6 +641,7 @@ void QTMovieWin::load(const UChar* url, int len) movieProps[moviePropCount].propStatus = 0; moviePropCount++; + ASSERT(moviePropCount <= sizeof(movieProps)/sizeof(movieProps[0])); m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, NULL, &m_private->m_movie); CFRelease(urlRef); @@ -601,15 +650,24 @@ end: // get the load fail callback quickly if (m_private->m_loadError) updateTaskTimer(0); - else + else { + OSType mode = kQTApertureMode_CleanAperture; + + // Set the aperture mode property on a movie to signal that we want aspect ratio + // and clean aperture dimensions. Don't worry about errors, we can't do anything if + // the installed version of QT doesn't support it and it isn't serious enough to + // warrant failing. + QTSetMovieProperty(m_private->m_movie, kQTPropertyClass_Visual, kQTVisualPropertyID_ApertureMode, sizeof(mode), &mode); m_private->registerDrawingCallback(); + } CFRelease(urlStringRef); } -void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount) +void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount) { if (!m_private->m_movie) { + totalTrackCount = 0; enabledTrackCount = 0; return; } @@ -623,11 +681,16 @@ void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount) allowedTrackTypes->add(BaseMediaType); 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(TimeCodeMediaType); + allowedTrackTypes->add(TimeCode64MediaType); } long trackCount = GetMovieTrackCount(m_private->m_movie); enabledTrackCount = trackCount; - + totalTrackCount = trackCount; + // Track indexes are 1-based. yuck. These things must descend from old- // school mac resources or something. for (long trackIndex = 1; trackIndex <= trackCount; trackIndex++) { @@ -716,6 +779,11 @@ void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount) } } +void QTMovieWin::setDisabled(bool b) +{ + m_disabled = b; +} + bool QTMovieWin::hasVideo() const { diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h index 2186974..70cbef5 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.h +++ b/WebCore/platform/graphics/win/QTMovieWin.h @@ -84,7 +84,8 @@ public: void setVisible(bool); void paint(HDC, int x, int y); - void disableUnsupportedTracks(unsigned& enabledTrackCount); + void disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount); + void setDisabled(bool); bool hasVideo() const; @@ -93,6 +94,7 @@ public: private: QTMovieWinPrivate* m_private; + bool m_disabled; friend class QTMovieWinPrivate; }; diff --git a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp index 8b5ab87..aaa089a 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp @@ -52,27 +52,27 @@ static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return unitsP void SimpleFontData::platformInit() { - m_syntheticBoldOffset = m_font.syntheticBold() ? 1.0f : 0.f; + m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; m_scriptCache = 0; m_scriptFontProperties = 0; m_isSystemFont = false; - if (m_font.useGDI()) + if (m_platformData.useGDI()) return initGDIFont(); - CGFontRef font = m_font.cgFont(); + CGFontRef font = m_platformData.cgFont(); int iAscent = CGFontGetAscent(font); int iDescent = CGFontGetDescent(font); int iLineGap = CGFontGetLeading(font); m_unitsPerEm = CGFontGetUnitsPerEm(font); - float pointSize = m_font.size(); + float pointSize = m_platformData.size(); float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize; float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize; float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize; if (!isCustomFont()) { HDC dc = GetDC(0); - HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); int faceLength = GetTextFace(dc, 0, 0); Vector<TCHAR> faceName(faceLength); GetTextFace(dc, faceLength, faceName.data()); @@ -116,6 +116,16 @@ void SimpleFontData::platformInit() } } +void SimpleFontData::platformCharWidthInit() +{ + // GDI Fonts init charwidths in initGDIFont. + if (!m_platformData.useGDI()) { + m_avgCharWidth = 0.f; + m_maxCharWidth = 0.f; + initCharWidths(); + } +} + void SimpleFontData::platformDestroy() { platformCommonDestroy(); @@ -123,11 +133,11 @@ void SimpleFontData::platformDestroy() float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { - if (m_font.useGDI()) + if (m_platformData.useGDI()) return widthForGDIGlyph(glyph); - CGFontRef font = m_font.cgFont(); - float pointSize = m_font.size(); + CGFontRef font = m_platformData.cgFont(); + float pointSize = m_platformData.size(); CGSize advance; CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize); diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp index 07d5305..2e51621 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp @@ -35,7 +35,6 @@ #include "FontCache.h" #include "FontDescription.h" #include "MathExtras.h" -#include "NotImplemented.h" #include <cairo.h> #include <cairo-win32.h> #include <mlang.h> @@ -50,14 +49,16 @@ void SimpleFontData::platformInit() m_isSystemFont = false; m_syntheticBoldOffset = 0; - if (m_font.useGDI()) + m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; + + if (m_platformData.useGDI()) return initGDIFont(); HDC hdc = GetDC(0); SaveDC(hdc); - cairo_scaled_font_t* scaledFont = m_font.scaledFont(); - const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_font.size(); + cairo_scaled_font_t* scaledFont = m_platformData.scaledFont(); + const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_platformData.size(); cairo_win32_scaled_font_select_font(scaledFont, hdc); @@ -68,6 +69,8 @@ void SimpleFontData::platformInit() m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts. m_lineGap = lroundf(textMetrics.tmExternalLeading * metricsMultiplier); m_lineSpacing = m_ascent + m_descent + m_lineGap; + m_avgCharWidth = lroundf(textMetrics.tmAveCharWidth * metricsMultiplier); + m_maxCharWidth = lroundf(textMetrics.tmMaxCharWidth * metricsMultiplier); OUTLINETEXTMETRIC metrics; if (GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics) > 0) { @@ -89,25 +92,30 @@ void SimpleFontData::platformInit() ReleaseDC(0, hdc); } +void SimpleFontData::platformCharWidthInit() +{ + // charwidths are set in platformInit. +} + void SimpleFontData::platformDestroy() { - cairo_font_face_destroy(m_font.fontFace()); - cairo_scaled_font_destroy(m_font.scaledFont()); + cairo_font_face_destroy(m_platformData.fontFace()); + cairo_scaled_font_destroy(m_platformData.scaledFont()); - DeleteObject(m_font.hfont()); + DeleteObject(m_platformData.hfont()); platformCommonDestroy(); } float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { - if (m_font.useGDI()) + if (m_platformData.useGDI()) return widthForGDIGlyph(glyph); HDC hdc = GetDC(0); SaveDC(hdc); - cairo_scaled_font_t* scaledFont = m_font.scaledFont(); + cairo_scaled_font_t* scaledFont = m_platformData.scaledFont(); cairo_win32_scaled_font_select_font(scaledFont, hdc); int width; @@ -118,14 +126,14 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const RestoreDC(hdc, -1); ReleaseDC(0, hdc); - const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_font.size(); + const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_platformData.size(); return width * metricsMultiplier; } void SimpleFontData::setFont(cairo_t* cr) const { ASSERT(cr); - m_font.setFont(cr); + m_platformData.setFont(cr); } } diff --git a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp index 9d5c3b9..9835e9f 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp @@ -63,7 +63,7 @@ bool SimpleFontData::shouldApplyMacAscentHack() void SimpleFontData::initGDIFont() { HDC hdc = GetDC(0); - HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont()); + HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); OUTLINETEXTMETRIC metrics; GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics); TEXTMETRIC& textMetrics = metrics.otmTextMetrics; @@ -71,6 +71,8 @@ void SimpleFontData::initGDIFont() m_descent = textMetrics.tmDescent; m_lineGap = textMetrics.tmExternalLeading; m_lineSpacing = m_ascent + m_descent + m_lineGap; + m_avgCharWidth = textMetrics.tmAveCharWidth; + m_maxCharWidth = textMetrics.tmMaxCharWidth; m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present. GLYPHMETRICS gm; @@ -100,17 +102,17 @@ void SimpleFontData::platformCommonDestroy() SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const { if (!m_smallCapsFontData) { - float smallCapsHeight = cSmallCapsFontSizeMultiplier * m_font.size(); + float smallCapsHeight = cSmallCapsFontSizeMultiplier * m_platformData.size(); if (isCustomFont()) { - FontPlatformData smallCapsFontData(m_font); + FontPlatformData smallCapsFontData(m_platformData); smallCapsFontData.setSize(smallCapsHeight); m_smallCapsFontData = new SimpleFontData(smallCapsFontData, true, false); } else { LOGFONT winfont; - GetObject(m_font.hfont(), sizeof(LOGFONT), &winfont); - winfont.lfHeight = -lroundf(smallCapsHeight * (m_font.useGDI() ? 1 : 32)); + GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winfont); + winfont.lfHeight = -lroundf(smallCapsHeight * (m_platformData.useGDI() ? 1 : 32)); HFONT hfont = CreateFontIndirect(&winfont); - m_smallCapsFontData = new SimpleFontData(FontPlatformData(hfont, smallCapsHeight, m_font.syntheticBold(), m_font.syntheticOblique(), m_font.useGDI())); + m_smallCapsFontData = new SimpleFontData(FontPlatformData(hfont, smallCapsHeight, m_platformData.syntheticBold(), m_platformData.syntheticOblique(), m_platformData.useGDI())); } } return m_smallCapsFontData; @@ -135,7 +137,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages); DWORD fontCodePages; - langFontLink->GetFontCodePages(dc, m_font.hfont(), &fontCodePages); + langFontLink->GetFontCodePages(dc, m_platformData.hfont(), &fontCodePages); DWORD actualCodePages; long numCharactersProcessed; @@ -162,7 +164,7 @@ void SimpleFontData::determinePitch() // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that. HDC dc = GetDC(0); SaveDC(dc); - SelectObject(dc, m_font.hfont()); + SelectObject(dc, m_platformData.hfont()); // Yes, this looks backwards, but the fixed pitch bit is actually set if the font // is *not* fixed pitch. Unbelievable but true. @@ -178,7 +180,7 @@ float SimpleFontData::widthForGDIGlyph(Glyph glyph) const { HDC hdc = GetDC(0); SetGraphicsMode(hdc, GM_ADVANCED); - HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont()); + HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); int width; GetCharWidthI(hdc, glyph, 1, 0, &width); SelectObject(hdc, oldFont); @@ -196,7 +198,7 @@ SCRIPT_FONTPROPERTIES* SimpleFontData::scriptFontProperties() const if (result == E_PENDING) { HDC dc = GetDC(0); SaveDC(dc); - SelectObject(dc, m_font.hfont()); + SelectObject(dc, m_platformData.hfont()); ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties); RestoreDC(dc, -1); ReleaseDC(0, dc); diff --git a/WebCore/platform/graphics/win/UniscribeController.cpp b/WebCore/platform/graphics/win/UniscribeController.cpp index 371bc51..f382857 100644 --- a/WebCore/platform/graphics/win/UniscribeController.cpp +++ b/WebCore/platform/graphics/win/UniscribeController.cpp @@ -38,9 +38,10 @@ namespace WebCore { // that does stuff in that method instead of doing everything in the constructor. Have advance() // take the GlyphBuffer as an arg so that we don't have to populate the glyph buffer when // measuring. -UniscribeController::UniscribeController(const Font* font, const TextRun& run) +UniscribeController::UniscribeController(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) : m_font(*font) , m_run(run) +, m_fallbackFonts(fallbackFonts) , m_end(run.length()) , m_currentCharacter(0) , m_runWidthSoFar(0) @@ -147,6 +148,9 @@ void UniscribeController::advance(unsigned offset, GlyphBuffer* glyphBuffer) smallCapsBuffer[index] = forceSmallCaps ? c : newC; } + if (m_fallbackFonts && nextFontData != fontData && fontData != m_font.primaryFont()) + m_fallbackFonts->add(fontData); + if (nextFontData != fontData || nextIsSmallCaps != isSmallCaps) { int itemStart = m_run.rtl() ? index + 1 : indexOfFontTransition; int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition; @@ -158,6 +162,9 @@ void UniscribeController::advance(unsigned offset, GlyphBuffer* glyphBuffer) int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : length - indexOfFontTransition; if (itemLength) { + if (m_fallbackFonts && nextFontData != m_font.primaryFont()) + m_fallbackFonts->add(nextFontData); + int itemStart = m_run.rtl() ? 0 : indexOfFontTransition; m_currentCharacter = baseCharacter + itemStart; itemizeShapeAndPlace((nextIsSmallCaps ? smallCapsBuffer.data() : cp) + itemStart, itemLength, nextFontData, glyphBuffer); @@ -258,16 +265,16 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S Vector<int> roundingHackWordBoundaries(glyphs.size()); roundingHackWordBoundaries.fill(-1); - const float cLogicalScale = fontData->m_font.useGDI() ? 1.0f : 32.0f; - unsigned logicalSpaceWidth = fontData->m_spaceWidth * cLogicalScale; - float roundedSpaceWidth = roundf(fontData->m_spaceWidth); + const float cLogicalScale = fontData->platformData().useGDI() ? 1.0f : 32.0f; + unsigned logicalSpaceWidth = fontData->spaceWidth() * cLogicalScale; + float roundedSpaceWidth = roundf(fontData->spaceWidth()); for (int k = 0; k < len; k++) { UChar ch = *(str + k); if (Font::treatAsSpace(ch)) { // Substitute in the space glyph at the appropriate place in the glyphs // array. - glyphs[clusters[k]] = fontData->m_spaceGlyph; + glyphs[clusters[k]] = fontData->spaceGlyph(); advances[clusters[k]] = logicalSpaceWidth; spaceCharacters[clusters[k]] = m_currentCharacter + k + item.iCharPos; } @@ -300,15 +307,15 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S offsetY = roundf(offsetY); } - advance += fontData->m_syntheticBoldOffset; + advance += 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 (roundedAdvance == roundedSpaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && + if (roundedAdvance == roundedSpaceWidth && (fontData->pitch() == FixedPitch || glyph == fontData->spaceGlyph()) && m_run.applyWordRounding()) - advance = fontData->m_adjustedSpaceWidth; + advance = fontData->adjustedSpaceWidth(); if (hasExtraSpacing) { // If we're a glyph with an advance, go ahead and add in letter-spacing. @@ -317,7 +324,7 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S advance += 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/win/UniscribeController.h b/WebCore/platform/graphics/win/UniscribeController.h index 6ea45e1..23b8108 100644 --- a/WebCore/platform/graphics/win/UniscribeController.h +++ b/WebCore/platform/graphics/win/UniscribeController.h @@ -38,7 +38,7 @@ namespace WebCore { class UniscribeController { public: - UniscribeController(const Font*, const TextRun&); + UniscribeController(const Font*, const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0); // Advance and measure/place up to the specified character. void advance(unsigned to, GlyphBuffer* = 0); @@ -60,6 +60,7 @@ private: const Font& m_font; const TextRun& m_run; + HashSet<const SimpleFontData*>* m_fallbackFonts; SCRIPT_CONTROL m_control; SCRIPT_STATE m_state; diff --git a/WebCore/platform/graphics/wx/FontWx.cpp b/WebCore/platform/graphics/wx/FontWx.cpp index 07223e9..04b2ec4 100644 --- a/WebCore/platform/graphics/wx/FontWx.cpp +++ b/WebCore/platform/graphics/wx/FontWx.cpp @@ -39,6 +39,11 @@ namespace WebCore { +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { @@ -63,7 +68,7 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRun& run, notImplemented(); } -float Font::floatWidthForComplexText(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const { notImplemented(); return 0; diff --git a/WebCore/platform/graphics/wx/ImageSourceWx.cpp b/WebCore/platform/graphics/wx/ImageSourceWx.cpp index fc8ce71..2f71d62 100644 --- a/WebCore/platform/graphics/wx/ImageSourceWx.cpp +++ b/WebCore/platform/graphics/wx/ImageSourceWx.cpp @@ -37,6 +37,9 @@ #include <wx/defs.h> #include <wx/bitmap.h> +#if USE(WXGC) +#include <wx/graphics.h> +#endif #include <wx/image.h> #include <wx/rawbmp.h> @@ -224,7 +227,14 @@ NativeImagePtr ImageSource::createFrameAtIndex(size_t index) bmp->UseAlpha(); #endif ASSERT(bmp->IsOk()); + +#if USE(WXGC) + wxGraphicsBitmap* bitmap = new wxGraphicsBitmap(wxGraphicsRenderer::GetDefaultRenderer()->CreateBitmap(*bmp)); + delete bmp; + return bitmap; +#else return bmp; +#endif } float ImageSource::frameDurationAtIndex(size_t index) diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp index e1d435e..b0a993e 100644 --- a/WebCore/platform/graphics/wx/ImageWx.cpp +++ b/WebCore/platform/graphics/wx/ImageWx.cpp @@ -26,11 +26,12 @@ #include "config.h" #include "Image.h" -#include "TransformationMatrix.h" #include "BitmapImage.h" +#include "FloatConversion.h" #include "FloatRect.h" #include "GraphicsContext.h" -#include "NotImplemented.h" +#include "ImageObserver.h" +#include "TransformationMatrix.h" #include <math.h> #include <stdio.h> @@ -98,13 +99,13 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR #if USE(WXGC) wxGCDC* context = (wxGCDC*)ctxt->platformContext(); wxGraphicsContext* gc = context->GetGraphicsContext(); + wxGraphicsBitmap* bitmap = frameAtIndex(m_currentFrame); #else wxWindowDC* context = ctxt->platformContext(); + wxBitmap* bitmap = frameAtIndex(m_currentFrame); #endif startAnimation(); - - wxBitmap* bitmap = frameAtIndex(m_currentFrame); if (!bitmap) // If it's too early we won't have an image yet. return; @@ -129,17 +130,15 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR adjustedDestRect.setLocation(FloatPoint(dst.x() - src.x() / scaleX, dst.y() - src.y() / scaleY)); adjustedDestRect.setSize(FloatSize(selfSize.width() / scaleX, selfSize.height() / scaleY)); } - - // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly. - int currHeight = bitmap->GetHeight(); - if (currHeight < selfSize.height()) - adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height()); - gc->PushState(); gc->Clip(dst.x(), dst.y(), dst.width(), dst.height()); +#if wxCHECK_VERSION(2,9,0) gc->DrawBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height()); - gc->PopState(); #else + gc->DrawGraphicsBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height()); +#endif + +#else // USE(WXGC) IntRect srcIntRect(src); IntRect dstIntRect(dst); bool rescaling = false; @@ -172,6 +171,9 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR #endif ctxt->restore(); + + if (ImageObserver* observer = imageObserver()) + observer->didDraw(this); } void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& dstRect) @@ -181,21 +183,29 @@ void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, c #if USE(WXGC) wxGCDC* context = (wxGCDC*)ctxt->platformContext(); + wxGraphicsBitmap* bitmap = frameAtIndex(m_currentFrame); #else wxWindowDC* context = ctxt->platformContext(); + wxBitmap* bitmap = frameAtIndex(m_currentFrame); #endif - ctxt->save(); - ctxt->clip(IntRect(dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height())); - wxBitmap* bitmap = frameAtIndex(m_currentFrame); if (!bitmap) // If it's too early we won't have an image yet. return; + + ctxt->save(); + ctxt->clip(IntRect(dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height())); float currentW = 0; float currentH = 0; #if USE(WXGC) wxGraphicsContext* gc = context->GetGraphicsContext(); + + float adjustedX = phase.x() + srcRect.x() * + narrowPrecisionToFloat(patternTransform.a()); + float adjustedY = phase.y() + srcRect.y() * + narrowPrecisionToFloat(patternTransform.d()); + gc->ConcatTransform(patternTransform); #else wxMemoryDC mydc; @@ -208,7 +218,11 @@ void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, c while ( currentW < dstRect.width() && currentW < clientSize.x - origin.x ) { while ( currentH < dstRect.height() && currentH < clientSize.y - origin.y) { #if USE(WXGC) - gc->DrawBitmap(*bitmap, (wxDouble)dstRect.x() + currentW, (wxDouble)dstRect.y() + currentH, (wxDouble)srcRect.width(), (wxDouble)srcRect.height()); +#if wxCHECK_VERSION(2,9,0) + gc->DrawBitmap(*bitmap, adjustedX + currentW, adjustedY + currentH, (wxDouble)srcRect.width(), (wxDouble)srcRect.height()); +#else + gc->DrawGraphicsBitmap(*bitmap, adjustedX + currentW, adjustedY + currentH, (wxDouble)srcRect.width(), (wxDouble)srcRect.height()); +#endif #else context->Blit((wxCoord)dstRect.x() + currentW, (wxCoord)dstRect.y() + currentH, (wxCoord)srcRect.width(), (wxCoord)srcRect.height(), &mydc, @@ -233,6 +247,8 @@ void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, c startAnimation(); + if (ImageObserver* observer = imageObserver()) + observer->didDraw(this); } void BitmapImage::checkForSolidColor() diff --git a/WebCore/platform/graphics/wx/PathWx.cpp b/WebCore/platform/graphics/wx/PathWx.cpp index 60c71d5..04a952d 100644 --- a/WebCore/platform/graphics/wx/PathWx.cpp +++ b/WebCore/platform/graphics/wx/PathWx.cpp @@ -66,11 +66,12 @@ Path::Path() Path::~Path() { + clear(); } Path::Path(const Path& path) { - m_path = (PlatformPath*)&path.m_path; + m_path = new wxGraphicsPath(*path.m_path); } bool Path::contains(const FloatPoint& point, const WindRule rule) const @@ -89,7 +90,7 @@ bool Path::contains(const FloatPoint& point, const WindRule rule) const void Path::translate(const FloatSize&) { - notImplemented(); + notImplemented(); } FloatRect Path::boundingRect() const diff --git a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp index ab50518..2368f83 100644 --- a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp +++ b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp @@ -45,7 +45,7 @@ namespace WebCore void SimpleFontData::platformInit() { - wxFont *font = m_font.font(); + wxFont *font = m_platformData.font(); if (font && font->IsOk()) { wxFontProperties props = wxFontProperties(font); m_ascent = props.GetAscent(); @@ -57,6 +57,13 @@ void SimpleFontData::platformInit() } } +void SimpleFontData::platformCharWidthInit() +{ + m_avgCharWidth = 0.f; + m_maxCharWidth = 0.f; + initCharWidths(); +} + void SimpleFontData::platformDestroy() { delete m_smallCapsFontData; @@ -81,8 +88,8 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con void SimpleFontData::determinePitch() { - if (m_font.font() && m_font.font()->Ok()) - m_treatAsFixedPitch = m_font.font()->IsFixedWidth(); + if (m_platformData.font() && m_platformData.font()->Ok()) + m_treatAsFixedPitch = m_platformData.font()->IsFixedWidth(); else m_treatAsFixedPitch = false; } @@ -91,7 +98,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const { // TODO: fix this! Make GetTextExtents a method of wxFont in 2.9 int width = 10; - GetTextExtent(*m_font.font(), (wxChar)glyph, &width, NULL); + GetTextExtent(*m_platformData.font(), (wxChar)glyph, &width, NULL); return width; } diff --git a/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp b/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp index f21dc17..9684a3c 100644 --- a/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp +++ b/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp @@ -26,9 +26,9 @@ #include "config.h" #include "TransformationMatrix.h" +#include "Assertions.h" #include "FloatRect.h" #include "IntRect.h" -#include "NotImplemented.h" #include <stdio.h> #include <wx/defs.h> |