From 4032fa1591d30d2c6a2b6b17d1362bf31f12f9e4 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 23 Dec 2014 12:50:10 +0000 Subject: [PATCH 01/17] Bug 1108616 - part 1 - Language-specific text-transform casing behavior should only be used when content was explicitly tagged for language. r=dbaron --- layout/generic/nsTextRunTransformations.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp index f43d100da7e5..91c4b9b3c1fe 100644 --- a/layout/generic/nsTextRunTransformations.cpp +++ b/layout/generic/nsTextRunTransformations.cpp @@ -311,8 +311,11 @@ nsCaseTransformTextRunFactory::TransformString( style = aAllUppercase ? NS_STYLE_TEXT_TRANSFORM_UPPERCASE : styleContext->StyleText()->mTextTransform; - if (lang != styleContext->StyleFont()->mLanguage) { - lang = styleContext->StyleFont()->mLanguage; + const nsStyleFont* styleFont = styleContext->StyleFont(); + nsIAtom* newLang = styleFont->mExplicitLanguage + ? styleFont->mLanguage : nullptr; + if (lang != newLang) { + lang = newLang; languageSpecificCasing = GetCasingFor(lang); greekState.Reset(); irishState.Reset(); From a896eab4249ce49176a944ffc862a5cf29a710f3 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 23 Dec 2014 12:50:10 +0000 Subject: [PATCH 02/17] Bug 1108616 - part 2 - Add an explicitLanguage field to gfxFontStyle, and pass it down from callers. r=dbaron --- dom/canvas/CanvasRenderingContext2D.cpp | 14 ++++++++++---- dom/canvas/CanvasRenderingContext2D.h | 7 +++++-- gfx/src/nsDeviceContext.cpp | 20 ++++++++++++-------- gfx/src/nsDeviceContext.h | 3 ++- gfx/src/nsFontMetrics.cpp | 4 +++- gfx/src/nsFontMetrics.h | 3 ++- gfx/thebes/gfxFont.cpp | 6 +++++- gfx/thebes/gfxFont.h | 7 ++++++- layout/base/nsLayoutUtils.cpp | 2 ++ layout/base/nsPresShell.cpp | 13 +++++-------- layout/generic/MathMLTextRunFactory.cpp | 4 +++- layout/generic/nsPageFrame.cpp | 2 +- layout/mathml/nsMathMLChar.cpp | 8 ++++++-- layout/style/nsRuleNode.cpp | 1 + 14 files changed, 63 insertions(+), 31 deletions(-) diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 1775b8b91d52..6c61cdabc942 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -2310,10 +2310,12 @@ class CanvasUserSpaceMetrics : public UserSpaceMetricsWithSize { public: CanvasUserSpaceMetrics(const gfx::IntSize& aSize, const nsFont& aFont, - nsIAtom* aFontLanguage, nsPresContext* aPresContext) + nsIAtom* aFontLanguage, bool aExplicitLanguage, + nsPresContext* aPresContext) : mSize(aSize) , mFont(aFont) , mFontLanguage(aFontLanguage) + , mExplicitLanguage(aExplicitLanguage) , mPresContext(aPresContext) { } @@ -2329,8 +2331,8 @@ public: gfxTextPerfMetrics* tp = mPresContext->GetTextPerfMetrics(); nsRefPtr fontMetrics; nsDeviceContext* dc = mPresContext->DeviceContext(); - dc->GetMetricsFor(mFont, mFontLanguage, gfxFont::eHorizontal, - nullptr, tp, + dc->GetMetricsFor(mFont, mFontLanguage, mExplicitLanguage, + gfxFont::eHorizontal, nullptr, tp, *getter_AddRefs(fontMetrics)); return NSAppUnitsToFloatPixels(fontMetrics->XHeight(), nsPresContext::AppUnitsPerCSSPixel()); @@ -2343,6 +2345,7 @@ private: gfx::IntSize mSize; const nsFont& mFont; nsIAtom* mFontLanguage; + bool mExplicitLanguage; nsPresContext* mPresContext; }; @@ -2360,6 +2363,7 @@ CanvasRenderingContext2D::UpdateFilter() CanvasUserSpaceMetrics(IntSize(mWidth, mHeight), CurrentState().fontFont, CurrentState().fontLanguage, + CurrentState().fontExplicitLanguage, presShell->GetPresContext()), gfxRect(0, 0, mWidth, mHeight), CurrentState().filterAdditionalImages); @@ -2991,7 +2995,7 @@ CanvasRenderingContext2D::SetFont(const nsAString& font, const nsStyleFont* fontStyle = sc->StyleFont(); - nsIAtom* language = sc->StyleFont()->mLanguage; + nsIAtom* language = fontStyle->mLanguage; if (!language) { language = presShell->GetPresContext()->GetLanguageFromCharset(); } @@ -3013,6 +3017,7 @@ CanvasRenderingContext2D::SetFont(const nsAString& font, fontStyle->mFont.stretch, NSAppUnitsToFloatPixels(fontStyle->mSize, float(aupcp)), language, + fontStyle->mExplicitLanguage, fontStyle->mFont.sizeAdjust, fontStyle->mFont.systemFont, printerFont, @@ -3033,6 +3038,7 @@ CanvasRenderingContext2D::SetFont(const nsAString& font, CurrentState().fontFont = fontStyle->mFont; CurrentState().fontFont.size = fontStyle->mSize; CurrentState().fontLanguage = fontStyle->mLanguage; + CurrentState().fontExplicitLanguage = fontStyle->mExplicitLanguage; } void diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index 8593502248dd..6c6991a04dd0 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -946,7 +946,8 @@ protected: fillRule(mozilla::gfx::FillRule::FILL_WINDING), lineCap(mozilla::gfx::CapStyle::BUTT), lineJoin(mozilla::gfx::JoinStyle::MITER_OR_BEVEL), - imageSmoothingEnabled(true) + imageSmoothingEnabled(true), + fontExplicitLanguage(false) { } ContextState(const ContextState& other) @@ -977,7 +978,8 @@ protected: filterChainObserver(other.filterChainObserver), filter(other.filter), filterAdditionalImages(other.filterAdditionalImages), - imageSmoothingEnabled(other.imageSmoothingEnabled) + imageSmoothingEnabled(other.imageSmoothingEnabled), + fontExplicitLanguage(other.fontExplicitLanguage) { } void SetColorStyle(Style whichStyle, nscolor color) @@ -1055,6 +1057,7 @@ protected: nsTArray> filterAdditionalImages; bool imageSmoothingEnabled; + bool fontExplicitLanguage; }; nsAutoTArray mStyleStack; diff --git a/gfx/src/nsDeviceContext.cpp b/gfx/src/nsDeviceContext.cpp index 3cd259be8be3..3b01dc7869e1 100644 --- a/gfx/src/nsDeviceContext.cpp +++ b/gfx/src/nsDeviceContext.cpp @@ -63,7 +63,8 @@ public: void Init(nsDeviceContext* aContext); void Destroy(); - nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage, + nsresult GetMetricsFor(const nsFont& aFont, + nsIAtom* aLanguage, bool aExplicitLanguage, gfxFont::Orientation aOrientation, gfxUserFontSet* aUserFontSet, gfxTextPerfMetrics* aTextPerf, @@ -124,7 +125,8 @@ nsFontCache::Observe(nsISupports*, const char* aTopic, const char16_t*) } nsresult -nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage, +nsFontCache::GetMetricsFor(const nsFont& aFont, + nsIAtom* aLanguage, bool aExplicitLanguage, gfxFont::Orientation aOrientation, gfxUserFontSet* aUserFontSet, gfxTextPerfMetrics* aTextPerf, @@ -157,8 +159,8 @@ nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage, fm = new nsFontMetrics(); NS_ADDREF(fm); - nsresult rv = fm->Init(aFont, aLanguage, aOrientation, mContext, - aUserFontSet, aTextPerf); + nsresult rv = fm->Init(aFont, aLanguage, aExplicitLanguage, aOrientation, + mContext, aUserFontSet, aTextPerf); if (NS_SUCCEEDED(rv)) { // the mFontMetrics list has the "head" at the end, because append // is cheaper than insert @@ -177,8 +179,8 @@ nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage, Compact(); fm = new nsFontMetrics(); NS_ADDREF(fm); - rv = fm->Init(aFont, aLanguage, aOrientation, mContext, aUserFontSet, - aTextPerf); + rv = fm->Init(aFont, aLanguage, aExplicitLanguage, aOrientation, mContext, + aUserFontSet, aTextPerf); if (NS_SUCCEEDED(rv)) { mFontMetrics.AppendElement(fm); aMetrics = fm; @@ -266,6 +268,7 @@ nsDeviceContext::~nsDeviceContext() nsresult nsDeviceContext::GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage, + bool aExplicitLanguage, gfxFont::Orientation aOrientation, gfxUserFontSet* aUserFontSet, gfxTextPerfMetrics* aTextPerf, @@ -277,8 +280,9 @@ nsDeviceContext::GetMetricsFor(const nsFont& aFont, mFontCache->Init(this); } - return mFontCache->GetMetricsFor(aFont, aLanguage, aOrientation, - aUserFontSet, aTextPerf, aMetrics); + return mFontCache->GetMetricsFor(aFont, aLanguage, aExplicitLanguage, + aOrientation, aUserFontSet, aTextPerf, + aMetrics); } nsresult diff --git a/gfx/src/nsDeviceContext.h b/gfx/src/nsDeviceContext.h index bd736c77b795..f4e033a41bcf 100644 --- a/gfx/src/nsDeviceContext.h +++ b/gfx/src/nsDeviceContext.h @@ -118,7 +118,8 @@ public: * @param aUserFontSet user font set * @return error status */ - nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage, + nsresult GetMetricsFor(const nsFont& aFont, + nsIAtom* aLanguage, bool aExplicitLanguage, gfxFont::Orientation aOrientation, gfxUserFontSet* aUserFontSet, gfxTextPerfMetrics* aTextPerf, diff --git a/gfx/src/nsFontMetrics.cpp b/gfx/src/nsFontMetrics.cpp index 95f2c4c5a30c..3f43d95e9e3f 100644 --- a/gfx/src/nsFontMetrics.cpp +++ b/gfx/src/nsFontMetrics.cpp @@ -103,7 +103,8 @@ nsFontMetrics::~nsFontMetrics() } nsresult -nsFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage, +nsFontMetrics::Init(const nsFont& aFont, + nsIAtom* aLanguage, bool aExplicitLanguage, gfxFont::Orientation aOrientation, nsDeviceContext *aContext, gfxUserFontSet *aUserFontSet, @@ -122,6 +123,7 @@ nsFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage, aFont.stretch, gfxFloat(aFont.size) / mP2A, aLanguage, + aExplicitLanguage, aFont.sizeAdjust, aFont.systemFont, mDeviceContext->IsPrinterSurface(), diff --git a/gfx/src/nsFontMetrics.h b/gfx/src/nsFontMetrics.h index 7d1d6c8d60c0..6e1249becdfb 100644 --- a/gfx/src/nsFontMetrics.h +++ b/gfx/src/nsFontMetrics.h @@ -56,7 +56,8 @@ public: * * @see nsDeviceContext#GetMetricsFor() */ - nsresult Init(const nsFont& aFont, nsIAtom* aLanguage, + nsresult Init(const nsFont& aFont, + nsIAtom* aLanguage, bool aExplicitLanguage, gfxFont::Orientation aOrientation, nsDeviceContext *aContext, gfxUserFontSet *aUserFontSet, diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index a6762b911019..1cd63fb32601 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -3584,13 +3584,15 @@ gfxFontStyle::gfxFontStyle() : style(NS_FONT_STYLE_NORMAL), allowSyntheticWeight(true), allowSyntheticStyle(true), noFallbackVariantFeatures(true), + explicitLanguage(false), variantCaps(NS_FONT_VARIANT_CAPS_NORMAL), variantSubSuper(NS_FONT_VARIANT_POSITION_NORMAL) { } gfxFontStyle::gfxFontStyle(uint8_t aStyle, uint16_t aWeight, int16_t aStretch, - gfxFloat aSize, nsIAtom *aLanguage, + gfxFloat aSize, + nsIAtom *aLanguage, bool aExplicitLanguage, float aSizeAdjust, bool aSystemFont, bool aPrinterFont, bool aAllowWeightSynthesis, @@ -3606,6 +3608,7 @@ gfxFontStyle::gfxFontStyle(uint8_t aStyle, uint16_t aWeight, int16_t aStretch, allowSyntheticWeight(aAllowWeightSynthesis), allowSyntheticStyle(aAllowStyleSynthesis), noFallbackVariantFeatures(true), + explicitLanguage(aExplicitLanguage), variantCaps(NS_FONT_VARIANT_CAPS_NORMAL), variantSubSuper(NS_FONT_VARIANT_POSITION_NORMAL) { @@ -3644,6 +3647,7 @@ gfxFontStyle::gfxFontStyle(const gfxFontStyle& aStyle) : allowSyntheticWeight(aStyle.allowSyntheticWeight), allowSyntheticStyle(aStyle.allowSyntheticStyle), noFallbackVariantFeatures(aStyle.noFallbackVariantFeatures), + explicitLanguage(aStyle.explicitLanguage), variantCaps(aStyle.variantCaps), variantSubSuper(aStyle.variantSubSuper) { diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index f176a4a985e0..c976de76ceda 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -61,7 +61,7 @@ class GlyphRenderingOptions; struct gfxFontStyle { gfxFontStyle(); gfxFontStyle(uint8_t aStyle, uint16_t aWeight, int16_t aStretch, - gfxFloat aSize, nsIAtom *aLanguage, + gfxFloat aSize, nsIAtom *aLanguage, bool aExplicitLanguage, float aSizeAdjust, bool aSystemFont, bool aPrinterFont, bool aWeightSynthesis, bool aStyleSynthesis, @@ -143,6 +143,10 @@ struct gfxFontStyle { // code, so set up a bool to indicate when shaping with fallback is needed bool noFallbackVariantFeatures : 1; + // whether the |language| field comes from explicit lang tagging in the + // document, or was inferred from charset/system locale + bool explicitLanguage : 1; + // caps variant (small-caps, petite-caps, etc.) uint8_t variantCaps; @@ -181,6 +185,7 @@ struct gfxFontStyle { (systemFont == other.systemFont) && (printerFont == other.printerFont) && (useGrayscaleAntialiasing == other.useGrayscaleAntialiasing) && + (explicitLanguage == other.explicitLanguage) && (weight == other.weight) && (stretch == other.stretch) && (language == other.language) && diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 8b4191545bcb..af859f5deb49 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -3782,6 +3782,7 @@ nsLayoutUtils::GetFontMetricsForStyleContext(nsStyleContext* aStyleContext, if (aInflation == 1.0f) { return pc->DeviceContext()->GetMetricsFor(styleFont->mFont, styleFont->mLanguage, + styleFont->mExplicitLanguage, orientation, fs, tp, *aFontMetrics); } @@ -3789,6 +3790,7 @@ nsLayoutUtils::GetFontMetricsForStyleContext(nsStyleContext* aStyleContext, nsFont font = styleFont->mFont; font.size = NSToCoordRound(font.size * aInflation); return pc->DeviceContext()->GetMetricsFor(font, styleFont->mLanguage, + styleFont->mExplicitLanguage, orientation, fs, tp, *aFontMetrics); } diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 1ad2cc8da9f0..8568bad00f31 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -10442,19 +10442,16 @@ void ReflowCountMgr::PaintCount(const char* aName, nsLayoutUtils::PointToGfxPoint(aOffset, appUnitsPerDevPixel); aRenderingContext->ThebesContext()->SetMatrix( aRenderingContext->ThebesContext()->CurrentMatrix().Translate(devPixelOffset)); + + // We don't care about the document language or user fonts here; + // just get a default Latin font. nsFont font(eFamily_serif, NS_FONT_STYLE_NORMAL, NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0, nsPresContext::CSSPixelsToAppUnits(11)); - nsRefPtr fm; aPresContext->DeviceContext()->GetMetricsFor(font, - // We have one frame, therefore we must have a root... - aPresContext->GetPresShell()->GetRootFrame()-> - StyleFont()->mLanguage, - gfxFont::eHorizontal, - aPresContext->GetUserFontSet(), - aPresContext->GetTextPerfMetrics(), - *getter_AddRefs(fm)); + nsGkAtoms::x_western, false, gfxFont::eHorizontal, nullptr, + aPresContext->GetTextPerfMetrics(), *getter_AddRefs(fm)); char buf[16]; int len = sprintf(buf, "%d", counter->mCount); diff --git a/layout/generic/MathMLTextRunFactory.cpp b/layout/generic/MathMLTextRunFactory.cpp index 9ab9f5665384..6485609a2ce0 100644 --- a/layout/generic/MathMLTextRunFactory.cpp +++ b/layout/generic/MathMLTextRunFactory.cpp @@ -739,8 +739,10 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, font.size = NSToCoordRound(font.size * mFontInflation); nsPresContext* pc = styles[0]->PresContext(); nsRefPtr metrics; + const nsStyleFont* styleFont = styles[0]->StyleFont(); pc->DeviceContext()->GetMetricsFor(font, - styles[0]->StyleFont()->mLanguage, + styleFont->mLanguage, + styleFont->mExplicitLanguage, gfxFont::eHorizontal, pc->GetUserFontSet(), pc->GetTextPerfMetrics(), diff --git a/layout/generic/nsPageFrame.cpp b/layout/generic/nsPageFrame.cpp index a8c1fbb1ee55..525a5172a09d 100644 --- a/layout/generic/nsPageFrame.cpp +++ b/layout/generic/nsPageFrame.cpp @@ -598,7 +598,7 @@ nsPageFrame::PaintHeaderFooter(nsRenderingContext& aRenderingContext, // Get the FontMetrics to determine width.height of strings nsRefPtr fontMet; - pc->DeviceContext()->GetMetricsFor(mPD->mHeadFootFont, nullptr, + pc->DeviceContext()->GetMetricsFor(mPD->mHeadFootFont, nullptr, false, gfxFont::eHorizontal, pc->GetUserFontSet(), pc->GetTextPerfMetrics(), diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index 71d02ddbb9dc..b03aa1627ae3 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -994,10 +994,12 @@ nsMathMLChar::SetFontFamily(nsPresContext* aPresContext, if (!*aFontGroup || !(aFont.fontlist == familyList)) { nsFont font = aFont; font.fontlist = familyList; + const nsStyleFont* styleFont = mStyleContext->StyleFont(); nsRefPtr fm; aPresContext->DeviceContext()-> GetMetricsFor(font, - mStyleContext->StyleFont()->mLanguage, + styleFont->mLanguage, + styleFont->mExplicitLanguage, gfxFont::eHorizontal, aPresContext->GetUserFontSet(), aPresContext->GetTextPerfMetrics(), @@ -1537,10 +1539,12 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext, nsFont font = mStyleContext->GetParent()->StyleFont()->mFont; NormalizeDefaultFont(font, aFontSizeInflation); + const nsStyleFont* styleFont = mStyleContext->StyleFont(); nsRefPtr fm; aPresContext->DeviceContext()-> GetMetricsFor(font, - mStyleContext->StyleFont()->mLanguage, + styleFont->mLanguage, + styleFont->mExplicitLanguage, gfxFont::eHorizontal, aPresContext->GetUserFontSet(), aPresContext->GetTextPerfMetrics(), diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 3a9a3d51183c..d4c683b191f4 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -298,6 +298,7 @@ GetMetricsFor(nsPresContext* aPresContext, nsRefPtr fm; aPresContext->DeviceContext()->GetMetricsFor(font, aStyleFont->mLanguage, + aStyleFont->mExplicitLanguage, orientation, fs, tp, *getter_AddRefs(fm)); return fm.forget(); From 3478d8e504fe6d3cc0af6fd6060015525d6aaaca Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 23 Dec 2014 12:50:10 +0000 Subject: [PATCH 03/17] Bug 1108616 - part 3 - Only do language-specific shaping when the language was explicitly tagged. r=jdaggett --- gfx/thebes/gfxFont.cpp | 6 ++++-- gfx/thebes/gfxGraphiteShaper.cpp | 2 +- gfx/thebes/gfxHarfBuzzShaper.cpp | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 1cd63fb32601..cb3940c0cfdb 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -2896,7 +2896,8 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, } else if (ch != ToLowerCase(ch)) { // ch is upper case chAction = (aSyntheticUpper ? kUppercaseReduce : kNoChange); - if (mStyle.language == nsGkAtoms::el) { + if (mStyle.explicitLanguage && + mStyle.language == nsGkAtoms::el) { // In Greek, check for characters that will be modified by // the GreekUpperCase mapping - this catches accented // capitals where the accent is to be removed (bug 307039). @@ -2948,7 +2949,8 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext, TransformString(origString, convertedString, true, - mStyle.language, + mStyle.explicitLanguage + ? mStyle.language : nullptr, charsToMergeArray, deletedCharsArray); diff --git a/gfx/thebes/gfxGraphiteShaper.cpp b/gfx/thebes/gfxGraphiteShaper.cpp index 68c832d27e8a..a31b24cf850c 100644 --- a/gfx/thebes/gfxGraphiteShaper.cpp +++ b/gfx/thebes/gfxGraphiteShaper.cpp @@ -145,7 +145,7 @@ gfxGraphiteShaper::ShapeText(gfxContext *aContext, grLang = MakeGraphiteLangTag(style->languageOverride); } else if (entry->mLanguageOverride) { grLang = MakeGraphiteLangTag(entry->mLanguageOverride); - } else { + } else if (style->explicitLanguage) { nsAutoCString langString; style->language->ToUTF8String(langString); grLang = GetGraphiteTagForLang(langString); diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp index f5dd79bb4fdc..1e28fab91015 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.cpp +++ b/gfx/thebes/gfxHarfBuzzShaper.cpp @@ -1228,11 +1228,13 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext, language = hb_ot_tag_to_language(style->languageOverride); } else if (entry->mLanguageOverride) { language = hb_ot_tag_to_language(entry->mLanguageOverride); - } else { + } else if (style->explicitLanguage) { nsCString langString; style->language->ToUTF8String(langString); language = hb_language_from_string(langString.get(), langString.Length()); + } else { + language = hb_ot_tag_to_language(HB_OT_TAG_DEFAULT_LANGUAGE); } hb_buffer_set_language(buffer, language); From 5b345c7a2fd7d73dca96f52e4f50a49a8d3693a6 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Tue, 19 Aug 2014 18:24:57 -0700 Subject: [PATCH 04/17] Bug 35168 (Part 1) - Add GetNormalRect to nsIFrame. r=dbaron --- layout/generic/nsFrame.cpp | 13 +++++++++++++ layout/generic/nsIFrame.h | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 7b37d0f6958e..df17edc914b1 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -5302,6 +5302,19 @@ nsIFrame::MovePositionBy(const nsPoint& aTranslation) SetPosition(position); } +nsRect +nsIFrame::GetNormalRect() const +{ + // It might be faster to first check + // StyleDisplay()->IsRelativelyPositionedStyle(). + nsPoint* normalPosition = static_cast + (Properties().Get(NormalPositionProperty())); + if (normalPosition) { + return nsRect(*normalPosition, GetSize()); + } + return GetRect(); +} + nsPoint nsIFrame::GetNormalPosition() const { diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 8dbeecfd5650..d9301964575a 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -749,6 +749,11 @@ public: MovePositionBy(aTranslation.GetPhysicalPoint(aWritingMode, 0)); } + /** + * Return frame's rect without relative positioning + */ + nsRect GetNormalRect() const; + /** * Return frame's position without relative positioning */ From 710bf88bca8ed5ee041c205a7b64f8cbfc8e5ff5 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Tue, 19 Aug 2014 18:24:58 -0700 Subject: [PATCH 05/17] Bug 35168 (Part 2) - Allow relative positioning of internal table objects. r=dbaron --- layout/base/RestyleManager.cpp | 14 ++- layout/tables/nsTableFrame.cpp | 134 ++++++++++++++----------- layout/tables/nsTableFrame.h | 1 + layout/tables/nsTablePainter.cpp | 121 +++++++++++++++++----- layout/tables/nsTablePainter.h | 29 +++++- layout/tables/nsTableRowFrame.cpp | 53 +++++++--- layout/tables/nsTableRowGroupFrame.cpp | 71 +++++++------ layout/tables/nsTableRowGroupFrame.h | 1 + 8 files changed, 285 insertions(+), 139 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index 4229e9a11af9..b55ec690ef89 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -410,16 +410,14 @@ RestyleManager::RecomputePosition(nsIFrame* aFrame) // For relative positioning, we can simply update the frame rect if (display->IsRelativelyPositionedStyle()) { - if (display->IsInnerTableStyle()) { - // We don't currently support relative positioning of inner table - // elements (bug 35168). If we apply offsets to things we haven't - // previously offset, we'll get confused. So bail. - return true; - } - - // Move the frame if (display->mPosition == NS_STYLE_POSITION_STICKY) { + if (display->IsInnerTableStyle()) { + // We don't currently support sticky positioning of inner table + // elements (bug 975644). Bail. + return true; + } + // Update sticky positioning for an entire element at once, starting with // the first continuation or ib-split sibling. // It's rare that the frame we already have isn't already the first diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 84d1731771ef..9a5a3370eb03 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1873,7 +1873,7 @@ nsTableFrame::Reflow(nsPresContext* aPresContext, // if there is an incomplete child, then set the desired height to include it but not the next one nsMargin borderPadding = GetChildAreaOffset(&aReflowState); aDesiredSize.Height() = borderPadding.bottom + GetCellSpacingY(GetRowCount()) + - lastChildReflowed->GetRect().YMost(); + lastChildReflowed->GetNormalRect().YMost(); } haveDesiredHeight = true; @@ -2677,6 +2677,7 @@ nsTableFrame::InitChildReflowState(nsHTMLReflowState& aReflowState) // aKidRect is relative to the upper-left origin of our frame void nsTableFrame::PlaceChild(nsTableReflowState& aReflowState, nsIFrame* aKidFrame, + nsPoint aKidPosition, nsHTMLReflowMetrics& aKidDesiredSize, const nsRect& aOriginalKidRect, const nsRect& aOriginalKidVisualOverflow) @@ -2686,7 +2687,7 @@ void nsTableFrame::PlaceChild(nsTableReflowState& aReflowState, // Place and size the child FinishReflowChild(aKidFrame, PresContext(), aKidDesiredSize, nullptr, - aReflowState.x, aReflowState.y, 0); + aKidPosition.x, aKidPosition.y, 0); InvalidateTableFrame(aKidFrame, aOriginalKidRect, aOriginalKidVisualOverflow, isFirstReflow); @@ -2870,7 +2871,10 @@ nsTableFrame::PlaceRepeatedFooter(nsTableReflowState& aReflowState, desiredSize.ClearSize(); ReflowChild(aTfoot, presContext, desiredSize, footerReflowState, aReflowState.x, aReflowState.y, 0, footerStatus); - PlaceChild(aReflowState, aTfoot, desiredSize, origTfootRect, + nsPoint kidPosition(aReflowState.x, aReflowState.y); + footerReflowState.ApplyRelativePositioning(&kidPosition); + + PlaceChild(aReflowState, aTfoot, kidPosition, desiredSize, origTfootRect, origTfootVisualOverflow); } @@ -2990,7 +2994,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, // We ignore a repeated head row group in this check to avoid causing // infinite loops in some circumstances - see bug 344883. if (childX > ((thead && IsRepeatedFrame(thead)) ? 1u : 0u) && - (rowGroups[childX - 1]->GetRect().YMost() > 0)) { + (rowGroups[childX - 1]->GetNormalRect().YMost() > 0)) { kidReflowState.mFlags.mIsTopOfPage = false; } aReflowState.y += cellSpacingY; @@ -3005,6 +3009,8 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, ReflowChild(kidFrame, presContext, desiredSize, kidReflowState, aReflowState.x, aReflowState.y, 0, aStatus); + nsPoint kidPosition(aReflowState.x, aReflowState.y); + kidReflowState.ApplyRelativePositioning(&kidPosition); if (reorder) { // reorder row groups the reflow may have changed the nextinflows @@ -3036,8 +3042,8 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, if (childX+1 < rowGroups.Length()) { nsIFrame* nextRowGroupFrame = rowGroups[childX + 1]; if (nextRowGroupFrame) { - PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect, - oldKidVisualOverflow); + PlaceChild(aReflowState, kidFrame, kidPosition, desiredSize, + oldKidRect, oldKidVisualOverflow); if (allowRepeatedFooter) { PlaceRepeatedFooter(aReflowState, tfoot, footerHeight); } @@ -3065,8 +3071,8 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, break; } else { // we can't push so lets make clear how much space we need - PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect, - oldKidVisualOverflow); + PlaceChild(aReflowState, kidFrame, kidPosition, desiredSize, + oldKidRect, oldKidVisualOverflow); aLastChildReflowed = kidFrame; if (allowRepeatedFooter) { PlaceRepeatedFooter(aReflowState, tfoot, footerHeight); @@ -3089,7 +3095,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, } // Place the child - PlaceChild(aReflowState, kidFrame, desiredSize, oldKidRect, + PlaceChild(aReflowState, kidFrame, kidPosition, desiredSize, oldKidRect, oldKidVisualOverflow); // Remember where we just were in case we end up pushing children @@ -3136,12 +3142,12 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState, } else { // it isn't being reflowed aReflowState.y += cellSpacingY; - nsRect kidRect = kidFrame->GetRect(); + nsRect kidRect = kidFrame->GetNormalRect(); if (kidRect.y != aReflowState.y) { // invalidate the old position kidFrame->InvalidateFrameSubtree(); - kidRect.y = aReflowState.y; - kidFrame->SetRect(kidRect); // move to the new position + // move to the new position + kidFrame->MovePositionBy(nsPoint(0, aReflowState.y - kidRect.y)); RePositionViews(kidFrame); // invalidate the new position kidFrame->InvalidateFrameSubtree(); @@ -3294,64 +3300,64 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState, nsTableRowGroupFrame* rgFrame = rowGroups[rgX]; nscoord amountUsedByRG = 0; nscoord yOriginRow = 0; - nsRect rgRect = rgFrame->GetRect(); + nsRect rgNormalRect = rgFrame->GetNormalRect(); if (!rgFrame->HasStyleHeight()) { nsTableRowFrame* rowFrame = rgFrame->GetFirstRow(); while (rowFrame) { - nsRect rowRect = rowFrame->GetRect(); + nsRect rowNormalRect = rowFrame->GetNormalRect(); nscoord cellSpacingY = GetCellSpacingY(rowFrame->GetRowIndex()); if ((amountUsed < aAmount) && rowFrame->HasPctHeight()) { nscoord pctHeight = rowFrame->GetHeight(pctBasis); - nscoord amountForRow = std::min(aAmount - amountUsed, pctHeight - rowRect.height); + nscoord amountForRow = std::min(aAmount - amountUsed, + pctHeight - rowNormalRect.height); if (amountForRow > 0) { - nsRect oldRowRect = rowRect; - rowRect.height += amountForRow; - // XXXbz we don't need to change rowRect.y to be yOriginRow? - rowFrame->SetRect(rowRect); - yOriginRow += rowRect.height + cellSpacingY; - yEndRG += rowRect.height + cellSpacingY; + // XXXbz we don't need to move the row's y position to yOriginRow? + nsRect origRowRect = rowFrame->GetRect(); + nscoord newRowHeight = rowNormalRect.height + amountForRow; + rowFrame->SetSize(nsSize(rowNormalRect.width, newRowHeight)); + yOriginRow += newRowHeight + cellSpacingY; + yEndRG += newRowHeight + cellSpacingY; amountUsed += amountForRow; amountUsedByRG += amountForRow; //rowFrame->DidResize(); nsTableFrame::RePositionViews(rowFrame); - rgFrame->InvalidateFrameWithRect(oldRowRect); + rgFrame->InvalidateFrameWithRect(origRowRect); rgFrame->InvalidateFrame(); } } else { - if (amountUsed > 0 && yOriginRow != rowRect.y && + if (amountUsed > 0 && yOriginRow != rowNormalRect.y && !(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { rowFrame->InvalidateFrameSubtree(); - rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow)); + rowFrame->MovePositionBy(nsPoint(0, yOriginRow - rowNormalRect.y)); nsTableFrame::RePositionViews(rowFrame); rowFrame->InvalidateFrameSubtree(); } - yOriginRow += rowRect.height + cellSpacingY; - yEndRG += rowRect.height + cellSpacingY; + yOriginRow += rowNormalRect.height + cellSpacingY; + yEndRG += rowNormalRect.height + cellSpacingY; } rowFrame = rowFrame->GetNextRow(); } if (amountUsed > 0) { - if (rgRect.y != yOriginRG) { + if (rgNormalRect.y != yOriginRG) { rgFrame->InvalidateFrameSubtree(); } - nsRect origRgRect = rgRect; + nsRect origRgNormalRect = rgFrame->GetRect(); nsRect origRgVisualOverflow = rgFrame->GetVisualOverflowRect(); - rgRect.y = yOriginRG; - rgRect.height += amountUsedByRG; + rgFrame->MovePositionBy(nsPoint(0, yOriginRG - rgNormalRect.y)); + rgFrame->SetSize(nsSize(rgNormalRect.width, + rgNormalRect.height + amountUsedByRG)); - rgFrame->SetRect(rgRect); - - nsTableFrame::InvalidateTableFrame(rgFrame, origRgRect, + nsTableFrame::InvalidateTableFrame(rgFrame, origRgNormalRect, origRgVisualOverflow, false); } } - else if (amountUsed > 0 && yOriginRG != rgRect.y) { + else if (amountUsed > 0 && yOriginRG != rgNormalRect.y) { rgFrame->InvalidateFrameSubtree(); - rgFrame->SetPosition(nsPoint(rgRect.x, yOriginRG)); + rgFrame->MovePositionBy(nsPoint(0, yOriginRG - rgNormalRect.y)); // Make sure child views are properly positioned nsTableFrame::RePositionViews(rgFrame); rgFrame->InvalidateFrameSubtree(); @@ -3431,14 +3437,14 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState, nsTableRowGroupFrame* rgFrame = rowGroups[rgX]; nscoord amountUsedByRG = 0; nscoord yOriginRow = 0; - nsRect rgRect = rgFrame->GetRect(); + nsRect rgNormalRect = rgFrame->GetNormalRect(); nsRect rgVisualOverflow = rgFrame->GetVisualOverflowRect(); // see if there is an eligible row group or we distribute to all rows if (!firstUnStyledRG || !rgFrame->HasStyleHeight() || !eligibleRows) { nsTableRowFrame* rowFrame = rgFrame->GetFirstRow(); while (rowFrame) { nscoord cellSpacingY = GetCellSpacingY(rowFrame->GetRowIndex()); - nsRect rowRect = rowFrame->GetRect(); + nsRect rowNormalRect = rowFrame->GetNormalRect(); nsRect rowVisualOverflow = rowFrame->GetVisualOverflowRect(); // see if there is an eligible row or we distribute to all rows if (!firstUnStyledRow || !rowFrame->HasStyleHeight() || !eligibleRows) { @@ -3447,7 +3453,7 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState, if (!expandEmptyRows) { // The amount of additional space each row gets is proportional to // its height - ratio = float(rowRect.height) / float(divisor); + ratio = float(rowNormalRect.height) / float(divisor); } else { // empty rows get all the same additional space ratio = 1.0f / float(eligibleRows); @@ -3463,17 +3469,18 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState, ? aAmount - amountUsed : NSToCoordRound(((float)(heightToDistribute)) * ratio); amountForRow = std::min(amountForRow, aAmount - amountUsed); - if (yOriginRow != rowRect.y) { + if (yOriginRow != rowNormalRect.y) { rowFrame->InvalidateFrameSubtree(); } // update the row height - nsRect newRowRect(rowRect.x, yOriginRow, rowRect.width, - rowRect.height + amountForRow); - rowFrame->SetRect(newRowRect); + nsRect origRowRect = rowFrame->GetRect(); + nscoord newRowHeight = rowNormalRect.height + amountForRow; + rowFrame->MovePositionBy(nsPoint(0, yOriginRow - rowNormalRect.y)); + rowFrame->SetSize(nsSize(rowNormalRect.width, newRowHeight)); - yOriginRow += newRowRect.height + cellSpacingY; - yEndRG += newRowRect.height + cellSpacingY; + yOriginRow += newRowHeight + cellSpacingY; + yEndRG += newRowHeight + cellSpacingY; amountUsed += amountForRow; amountUsedByRG += amountForRow; @@ -3481,37 +3488,39 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState, //rowFrame->DidResize(); nsTableFrame::RePositionViews(rowFrame); - nsTableFrame::InvalidateTableFrame(rowFrame, rowRect, rowVisualOverflow, - false); + nsTableFrame::InvalidateTableFrame(rowFrame, origRowRect, + rowVisualOverflow, false); } else { - if (amountUsed > 0 && yOriginRow != rowRect.y) { + if (amountUsed > 0 && yOriginRow != rowNormalRect.y) { rowFrame->InvalidateFrameSubtree(); - rowFrame->SetPosition(nsPoint(rowRect.x, yOriginRow)); + rowFrame->MovePositionBy(nsPoint(0, yOriginRow - rowNormalRect.y)); nsTableFrame::RePositionViews(rowFrame); rowFrame->InvalidateFrameSubtree(); } - yOriginRow += rowRect.height + cellSpacingY; - yEndRG += rowRect.height + cellSpacingY; + yOriginRow += rowNormalRect.height + cellSpacingY; + yEndRG += rowNormalRect.height + cellSpacingY; } rowFrame = rowFrame->GetNextRow(); } if (amountUsed > 0) { - if (rgRect.y != yOriginRG) { + if (rgNormalRect.y != yOriginRG) { rgFrame->InvalidateFrameSubtree(); } - rgFrame->SetRect(nsRect(rgRect.x, yOriginRG, rgRect.width, - rgRect.height + amountUsedByRG)); + nsRect origRgNormalRect = rgFrame->GetRect(); + rgFrame->MovePositionBy(nsPoint(0, yOriginRG - rgNormalRect.y)); + rgFrame->SetSize(nsSize(rgNormalRect.width, + rgNormalRect.height + amountUsedByRG)); - nsTableFrame::InvalidateTableFrame(rgFrame, rgRect, rgVisualOverflow, - false); + nsTableFrame::InvalidateTableFrame(rgFrame, origRgNormalRect, + rgVisualOverflow, false); } // Make sure child views are properly positioned } - else if (amountUsed > 0 && yOriginRG != rgRect.y) { + else if (amountUsed > 0 && yOriginRG != rgNormalRect.y) { rgFrame->InvalidateFrameSubtree(); - rgFrame->SetPosition(nsPoint(rgRect.x, yOriginRG)); + rgFrame->MovePositionBy(nsPoint(0, yOriginRG - rgNormalRect.y)); // Make sure child views are properly positioned nsTableFrame::RePositionViews(rgFrame); rgFrame->InvalidateFrameSubtree(); @@ -3611,8 +3620,15 @@ nsTableFrame::GetLogicalBaseline(WritingMode aWritingMode) const nsTableRowGroupFrame* rgFrame = orderedRowGroups[rgIndex]; if (rgFrame->GetRowCount()) { firstRow = rgFrame->GetFirstRow(); - ascent = rgFrame->BStart(aWritingMode, containerWidth) + - firstRow->BStart(aWritingMode, containerWidth) + + + nscoord rgNormalBStart = + LogicalRect(aWritingMode, rgFrame->GetNormalRect(), containerWidth) + .Origin(aWritingMode).B(aWritingMode); + nscoord firstRowNormalBStart = + LogicalRect(aWritingMode, firstRow->GetNormalRect(), containerWidth) + .Origin(aWritingMode).B(aWritingMode); + + ascent = rgNormalBStart + firstRowNormalBStart + firstRow->GetRowBaseline(aWritingMode); break; } diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index cfc25b48d669..95640a7ef3da 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -679,6 +679,7 @@ protected: void PlaceChild(nsTableReflowState& aReflowState, nsIFrame* aKidFrame, + nsPoint aKidPosition, nsHTMLReflowMetrics& aKidDesiredSize, const nsRect& aOriginalKidRect, const nsRect& aOriginalKidVisualOverflow); diff --git a/layout/tables/nsTablePainter.cpp b/layout/tables/nsTablePainter.cpp index 6250ba1c40c9..59db57bfa335 100644 --- a/layout/tables/nsTablePainter.cpp +++ b/layout/tables/nsTablePainter.cpp @@ -92,11 +92,7 @@ Elements with stacking contexts set up their own painter to finish the painting process, since they were skipped. They call the appropriate sub-part of the loop (e.g. PaintRow) which will paint the frame and - descendants. Note that it is permissible according to CSS2.1 to ignore' - 'position:relative' (and implicitly, 'opacity') on table parts so that - table parts can never create stacking contexts; if we want to, we can - implement that, and then we won't have to deal with TableBackgroundPainter - being used anywhere but from the nsTableFrame. + descendants. XXX views are going */ @@ -422,7 +418,15 @@ TableBackgroundPainter::PaintTable(nsTableFrame* aTableFrame, // Need to compute the right rect via GetOffsetTo, since the row // group may not be a child of the table. mRowGroup.mRect.MoveTo(rg->GetOffsetTo(aTableFrame)); - if (mRowGroup.mRect.Intersects(mDirtyRect - mRenderPt)) { + + // We have to draw backgrounds not only within the overflow region of this + // row group, but also possibly (in the case of column / column group + // backgrounds) at its pre-relative-positioning location. + nsRect rgVisualOverflow = rg->GetVisualOverflowRectRelativeToSelf(); + nsRect rgOverflowRect = rgVisualOverflow + rg->GetPosition(); + nsRect rgNormalRect = rgVisualOverflow + rg->GetNormalPosition(); + + if (rgOverflowRect.Union(rgNormalRect).Intersects(mDirtyRect - mRenderPt)) { nsresult rv = PaintRowGroup(rg, rg->IsPseudoStackingContextFromStyle()); if (NS_FAILED(rv)) return rv; } @@ -470,16 +474,12 @@ TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame, mRowGroup.mRect.MoveTo(0, 0); /* Find the right row to start with */ - nscoord ignored; // We don't care about overflow above, since what we really - // care about are backgrounds and overflow above doesn't - // correspond to backgrounds, since cells can't span up from - // their originating row. We do care about overflow below, - // however, since that can be due to rowspans. // Note that mDirtyRect - mRenderPt is guaranteed to be in the row // group's coordinate system here, so passing its .y to // GetFirstRowContaining is ok. - nsIFrame* cursor = aFrame->GetFirstRowContaining(mDirtyRect.y - mRenderPt.y, &ignored); + nscoord overflowAbove; + nsIFrame* cursor = aFrame->GetFirstRowContaining(mDirtyRect.y - mRenderPt.y, &overflowAbove); // Sadly, it seems like there may be non-row frames in there... or something? // There are certainly null-checks in GetFirstRow() and GetNextRow(). :( @@ -500,9 +500,13 @@ TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame, /* Finally paint */ for (; row; row = row->GetNextRow()) { mRow.SetFrame(row); - if (mDirtyRect.YMost() - mRenderPt.y < mRow.mRect.y) { // Intersect wouldn't handle - // rowspans. + // Be sure to consider our positions both pre- and post-relative + // positioning, since we potentially need to paint at both places. + nscoord rowY = std::min(mRow.mRect.y, row->GetNormalPosition().y); + // Intersect wouldn't handle rowspans. + if (cursor && + (mDirtyRect.YMost() - mRenderPt.y) <= (rowY - overflowAbove)) { // All done; cells originating in later rows can't intersect mDirtyRect. break; } @@ -564,10 +568,20 @@ TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame, //else: Use row group's coord system -> no translation necessary for (nsTableCellFrame* cell = aFrame->GetFirstCell(); cell; cell = cell->GetNextCell()) { - //Translate to use the same coord system as mRow. - mCellRect = cell->GetRect() + mRow.mRect.TopLeft() + mRenderPt; - if (mCellRect.Intersects(mDirtyRect)) { - nsresult rv = PaintCell(cell, aPassThrough || cell->IsPseudoStackingContextFromStyle()); + nsRect cellBGRect, rowBGRect, rowGroupBGRect, colBGRect; + ComputeCellBackgrounds(cell, cellBGRect, rowBGRect, + rowGroupBGRect, colBGRect); + + // Find the union of all the cell background layers. + nsRect combinedRect(cellBGRect); + combinedRect.UnionRect(combinedRect, rowBGRect); + combinedRect.UnionRect(combinedRect, rowGroupBGRect); + combinedRect.UnionRect(combinedRect, colBGRect); + + if (combinedRect.Intersects(mDirtyRect)) { + bool passCell = aPassThrough || cell->IsPseudoStackingContextFromStyle(); + nsresult rv = PaintCell(cell, cellBGRect, rowBGRect, rowGroupBGRect, + colBGRect, passCell); if (NS_FAILED(rv)) return rv; } } @@ -579,7 +593,11 @@ TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame, nsresult TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell, - bool aPassSelf) + nsRect& aCellBGRect, + nsRect& aRowBGRect, + nsRect& aRowGroupBGRect, + nsRect& aColBGRect, + bool aPassSelf) { NS_PRECONDITION(aCell, "null frame"); @@ -603,7 +621,7 @@ TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell, mCols[colIndex].mColGroup->mRect + mRenderPt, mCols[colIndex].mColGroup->mFrame->StyleContext(), *mCols[colIndex].mColGroup->mBorder, - mBGPaintFlags, &mCellRect); + mBGPaintFlags, &aColBGRect); } //Paint column background @@ -613,7 +631,7 @@ TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell, mCols[colIndex].mCol.mRect + mRenderPt, mCols[colIndex].mCol.mFrame->StyleContext(), *mCols[colIndex].mCol.mBorder, - mBGPaintFlags, &mCellRect); + mBGPaintFlags, &aColBGRect); } //Paint row group background @@ -623,7 +641,7 @@ TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell, mRowGroup.mRect + mRenderPt, mRowGroup.mFrame->StyleContext(), *mRowGroup.mBorder, - mBGPaintFlags, &mCellRect); + mBGPaintFlags, &aRowGroupBGRect); } //Paint row background @@ -633,14 +651,69 @@ TableBackgroundPainter::PaintCell(nsTableCellFrame* aCell, mRow.mRect + mRenderPt, mRow.mFrame->StyleContext(), *mRow.mBorder, - mBGPaintFlags, &mCellRect); + mBGPaintFlags, &aRowBGRect); } //Paint cell background in border-collapse unless we're just passing if (mIsBorderCollapse && !aPassSelf) { aCell->PaintCellBackground(mRenderingContext, mDirtyRect, - mCellRect.TopLeft(), mBGPaintFlags); + aCellBGRect.TopLeft(), mBGPaintFlags); } return NS_OK; } + +void +TableBackgroundPainter::ComputeCellBackgrounds(nsTableCellFrame* aCell, + nsRect& aCellBGRect, + nsRect& aRowBGRect, + nsRect& aRowGroupBGRect, + nsRect& aColBGRect) +{ + // We need to compute table background layer rects for this cell space, + // adjusted for possible relative positioning. This behavior is not specified + // at the time of this writing, but the approach below should be web + // compatible. + // + // Our goal is that relative positioning of a table part should leave + // backgrounds *under* that part unchanged. ("Under" being defined by CSS 2.1 + // Section 17.5.1.) If a cell is positioned, we do not expect the row + // background to move. On the other hand, the backgrounds of layers *above* + // the positioned part are taken along for the ride -- for example, + // positioning a row group will also cause the row background to be drawn in + // the new location, unless it has further positioning applied. + // + // Each table part layer has its position stored in the coordinate space of + // the layer below (which is to say, its geometric parent), and the stored + // position is the post-relative-positioning one. The position of each + // background layer rect is thus determined by peeling off successive table + // part layers, removing the contribution of each layer's positioning one by + // one. Every rect we generate will be the same size, the size of the cell + // space. + + // We cannot rely on the row group background data to be available, since some + // callers enter through PaintRow. + nsIFrame* rowGroupFrame = + mRowGroup.mFrame ? mRowGroup.mFrame : mRow.mFrame->GetParent(); + + // The cell background goes at the cell's position, translated to use the same + // coordinate system as mRow. + aCellBGRect = aCell->GetRect() + mRow.mRect.TopLeft() + mRenderPt; + + // The row background goes at the normal position of the cell, which is to say + // the position without relative positioning applied. + aRowBGRect = aCellBGRect + (aCell->GetNormalPosition() - aCell->GetPosition()); + + // The row group background goes at the position we'd find the cell if neither + // the cell's relative positioning nor the row's were applied. + aRowGroupBGRect = aRowBGRect + + (mRow.mFrame->GetNormalPosition() - mRow.mFrame->GetPosition()); + + // The column and column group backgrounds (they're always at the same + // location, since relative positioning doesn't apply to columns or column + // groups) are drawn at the position we'd find the cell if none of the cell's, + // row's, or row group's relative positioning were applied. + aColBGRect = aRowGroupBGRect + + (rowGroupFrame->GetNormalPosition() - rowGroupFrame->GetPosition()); + +} diff --git a/layout/tables/nsTablePainter.h b/layout/tables/nsTablePainter.h index bc00642a370b..73d2874a09ac 100644 --- a/layout/tables/nsTablePainter.h +++ b/layout/tables/nsTablePainter.h @@ -131,12 +131,34 @@ class TableBackgroundPainter /** Paint table background layers for this cell space * Also paints cell's own background in border-collapse mode - * @param aFrame - the cell - * @param aPassSelf - pass this cell; i.e. paint only underlying layers + * @param aCell - the cell + * @param aCellBGRect - background rect for the cell + * @param aRowBGRect - background rect for the row + * @param aRowGroupBGRect - background rect for the row group + * @param aColBGRect - background rect for the column and column group + * @param aPassSelf - pass this cell; i.e. paint only underlying layers */ - nsresult PaintCell(nsTableCellFrame* aFrame, + nsresult PaintCell(nsTableCellFrame* aCell, + nsRect& aCellBGRect, + nsRect& aRowBGRect, + nsRect& aRowGroupBGRect, + nsRect& aColBGRect, bool aPassSelf); + /** Compute table background layer positions for this cell space + * @param aCell - the cell + * @param aCellBGRectOut - outparam: background rect for the cell + * @param aRowBGRectOut - outparam: background rect for the row + * @param aRowGroupBGRectOut - outparam: background rect for the row group + * @param aColBGRectOut - outparam: background rect for the column + and column group + */ + void ComputeCellBackgrounds(nsTableCellFrame* aCell, + nsRect& aCellBGRect, + nsRect& aRowBGRect, + nsRect& aRowGroupBGRect, + nsRect& aColBGRect); + /** Translate mRenderingContext, mDirtyRect, and mCols' column and * colgroup coords * @param aDX - origin's x-coord change @@ -214,7 +236,6 @@ class TableBackgroundPainter uint32_t mNumCols; TableBackgroundData mRowGroup; //current row group TableBackgroundData mRow; //current row - nsRect mCellRect; //current cell's rect nsStyleBorder mZeroBorder; //cached zero-width border uint32_t mBGPaintFlags; diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp index 77f09d84be5d..15963f050a02 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -2,6 +2,9 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Maybe.h" + #include "nsTableRowFrame.h" #include "nsTableRowGroupFrame.h" #include "nsIPresShell.h" @@ -395,7 +398,7 @@ nscoord nsTableRowFrame::GetRowBaseline(WritingMode aWritingMode) while (childFrame) { if (IS_TABLE_CELL(childFrame->GetType())) { nsIFrame* firstKid = childFrame->GetFirstPrincipalChild(); - ascent = std::max(ascent, firstKid->GetRect().YMost()); + ascent = std::max(ascent, firstKid->GetNormalRect().YMost()); } // Get the next child childFrame = iter.Next(); @@ -861,7 +864,10 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, // Reflow the child frame nsRect kidRect = kidFrame->GetRect(); + nsPoint origKidNormalPosition = kidFrame->GetNormalPosition(); + MOZ_ASSERT(origKidNormalPosition.y == 0); nsRect kidVisualOverflow = kidFrame->GetVisualOverflowRect(); + nsPoint kidPosition(x, 0); bool firstReflow = (kidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; @@ -870,6 +876,7 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, nscoord availCellWidth = CalcAvailWidth(aTableFrame, *cellFrame); + Maybe kidReflowState; nsHTMLReflowMetrics desiredSize(aReflowState); // If the avail width is not the same as last time we reflowed the cell or @@ -890,19 +897,19 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, HasPctHeight()) { // Reflow the cell to fit the available width, height // XXX The old IR_ChildIsDirty code used availCellWidth here. - nsSize kidAvailSize(availCellWidth, aReflowState.AvailableHeight()); + nsSize kidAvailSize(availCellWidth, aReflowState.AvailableHeight()); // Reflow the child - nsTableCellReflowState - kidReflowState(aPresContext, aReflowState, kidFrame, - LogicalSize(kidFrame->GetWritingMode(), - kidAvailSize), - nsHTMLReflowState::CALLER_WILL_INIT); + kidReflowState.emplace(aPresContext, aReflowState, kidFrame, + LogicalSize(kidFrame->GetWritingMode(), + kidAvailSize), + // Cast needed for gcc 4.4. + uint32_t(nsHTMLReflowState::CALLER_WILL_INIT)); InitChildReflowState(*aPresContext, kidAvailSize, borderCollapse, - kidReflowState); + *kidReflowState); nsReflowStatus status; - ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, + ReflowChild(kidFrame, aPresContext, desiredSize, *kidReflowState, x, 0, 0, status); // allow the table to determine if/how the table needs to be rebalanced @@ -912,7 +919,7 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, } } else { - if (x != kidRect.x) { + if (x != origKidNormalPosition.x) { kidFrame->InvalidateFrameSubtree(); } @@ -956,7 +963,18 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, // Place the child desiredSize.ISize(rowWM) = availCellWidth; - FinishReflowChild(kidFrame, aPresContext, desiredSize, nullptr, x, 0, 0); + if (kidReflowState) { + // We reflowed. Apply relative positioning in the normal way. + kidReflowState->ApplyRelativePositioning(&kidPosition); + } else { + // We didn't reflow. To take relative positioning into account, + // translate the new position by the vector from the previous 'normal' + // position to the previous position. + // XXX(seth): This doesn't work for 'position: sticky'. + kidPosition += kidRect.TopLeft() - origKidNormalPosition; + } + FinishReflowChild(kidFrame, aPresContext, desiredSize, nullptr, + kidPosition.x, kidPosition.y, 0); nsTableFrame::InvalidateTableFrame(kidFrame, kidRect, kidVisualOverflow, firstReflow); @@ -964,11 +982,12 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, x += desiredSize.Width(); } else { - if (kidRect.x != x) { + if (x != origKidNormalPosition.x) { // Invalidate the old position kidFrame->InvalidateFrameSubtree(); - // move to the new position - kidFrame->SetPosition(nsPoint(x, kidRect.y)); + // Move to the new position. As above, we need to account for relative + // positioning. + kidFrame->MovePositionBy(nsPoint(x - origKidNormalPosition.x, 0)); nsTableFrame::RePositionViews(kidFrame); // invalidate the new position kidFrame->InvalidateFrameSubtree(); @@ -1263,14 +1282,16 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset, } nsRect oldCellRect = cellFrame->GetRect(); + nsPoint oldCellNormalPos = cellFrame->GetNormalPosition(); nsRect oldCellVisualOverflow = cellFrame->GetVisualOverflowRect(); - if (aRowOffset == 0 && cRect.TopLeft() != oldCellRect.TopLeft()) { + if (aRowOffset == 0 && cRect.TopLeft() != oldCellNormalPos) { // We're moving the cell. Invalidate the old overflow area cellFrame->InvalidateFrameSubtree(); } - cellFrame->SetRect(cRect); + cellFrame->MovePositionBy(cRect.TopLeft() - oldCellNormalPos); + cellFrame->SetSize(cRect.Size()); // XXXbz This looks completely bogus in the cases when we didn't // collapse the cell! diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index 2082ad9231a0..35e29268d5f3 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -205,7 +205,8 @@ DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame, if (kid) { // have a cursor, use it while (kid) { - if (kid->GetRect().y - overflowAbove >= aDirtyRect.YMost()) + if (kid->GetRect().y - overflowAbove >= aDirtyRect.YMost() && + kid->GetNormalRect().y - overflowAbove >= aDirtyRect.YMost()) break; f->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); kid = kid->GetNextSibling(); @@ -277,6 +278,7 @@ void nsTableRowGroupFrame::PlaceChild(nsPresContext* aPresContext, nsRowGroupReflowState& aReflowState, nsIFrame* aKidFrame, + nsPoint aKidPosition, nsHTMLReflowMetrics& aDesiredSize, const nsRect& aOriginalKidRect, const nsRect& aOriginalKidVisualOverflow) @@ -285,8 +287,8 @@ nsTableRowGroupFrame::PlaceChild(nsPresContext* aPresContext, (aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; // Place and size the child - FinishReflowChild(aKidFrame, aPresContext, aDesiredSize, nullptr, 0, - aReflowState.y, 0); + FinishReflowChild(aKidFrame, aPresContext, aDesiredSize, nullptr, + aKidPosition.x, aKidPosition.y, 0); nsTableFrame::InvalidateTableFrame(aKidFrame, aOriginalKidRect, aOriginalKidVisualOverflow, isFirstReflow); @@ -400,16 +402,18 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext, "If we're not on the first frame, we should have a " "previous sibling..."); // If prev row has nonzero YMost, then we can't be at the top of the page - if (prevKidFrame && prevKidFrame->GetRect().YMost() > 0) { + if (prevKidFrame && prevKidFrame->GetNormalRect().YMost() > 0) { kidReflowState.mFlags.mIsTopOfPage = false; } ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, 0, aReflowState.y, 0, aStatus); + nsPoint kidPosition(0, aReflowState.y); + kidReflowState.ApplyRelativePositioning(&kidPosition); // Place the child - PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize, - oldKidRect, oldKidVisualOverflow); + PlaceChild(aPresContext, aReflowState, kidFrame, kidPosition, + desiredSize, oldKidRect, oldKidVisualOverflow); aReflowState.y += cellSpacingY; if (!reflowAllKids) { @@ -423,8 +427,6 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext, unit != eStyleUnit_Coord) { // Because other cells in the row may need to be aligned // differently, repaint the entire row - nsRect kidRect(0, aReflowState.y, - desiredSize.Width(), desiredSize.Height()); InvalidateFrame(); } else if (oldKidRect.height != desiredSize.Height()) @@ -549,7 +551,7 @@ nsTableRowGroupFrame::CalculateRowHeights(nsPresContext* aPresContext, if (!startRowFrame) return; // the current row group height is the y origin of the 1st row we are about to calculated a height for - nscoord startRowGroupHeight = startRowFrame->GetPosition().y; + nscoord startRowGroupHeight = startRowFrame->GetNormalPosition().y; int32_t numRows = GetRowCount() - (startRowFrame->GetRowIndex() - GetStartRowIndex()); // collect the current height of each row. nscoord* rowHeights = nullptr; @@ -778,25 +780,26 @@ nsTableRowGroupFrame::CalculateRowHeights(nsPresContext* aPresContext, for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) { nsRect rowBounds = rowFrame->GetRect(); nsRect rowVisualOverflow = rowFrame->GetVisualOverflowRect(); + nscoord deltaY = yOrigin - rowFrame->GetNormalPosition().y; - bool movedFrame = (rowBounds.y != yOrigin); nscoord rowHeight = (rowInfo[rowIndex].height > 0) ? rowInfo[rowIndex].height : 0; - if (movedFrame || (rowHeight != rowBounds.height)) { + if (deltaY != 0 || (rowHeight != rowBounds.height)) { // Resize/move the row to its final size and position - if (movedFrame) { + if (deltaY != 0) { rowFrame->InvalidateFrameSubtree(); } - rowFrame->SetRect(nsRect(rowBounds.x, yOrigin, rowBounds.width, - rowHeight)); + rowFrame->MovePositionBy(nsPoint(0, deltaY)); + rowFrame->SetSize(nsSize(rowBounds.width, rowHeight)); nsTableFrame::InvalidateTableFrame(rowFrame, rowBounds, rowVisualOverflow, false); - } - if (movedFrame) { - nsTableFrame::RePositionViews(rowFrame); - // XXXbz we don't need to update our overflow area? + + if (deltaY != 0) { + nsTableFrame::RePositionViews(rowFrame); + // XXXbz we don't need to update our overflow area? + } } yOrigin += rowHeight + tableFrame->GetCellSpacingY(startRowIndex + rowIndex); } @@ -869,11 +872,12 @@ nsTableRowGroupFrame::SlideChild(nsRowGroupReflowState& aReflowState, nsIFrame* aKidFrame) { // Move the frame if we need to - nsPoint oldPosition = aKidFrame->GetPosition(); + nsPoint oldPosition = aKidFrame->GetNormalPosition(); nsPoint newPosition = oldPosition; newPosition.y = aReflowState.y; if (oldPosition.y != newPosition.y) { aKidFrame->InvalidateFrameSubtree(); + aReflowState.reflowState.ApplyRelativePositioning(&newPosition); aKidFrame->SetPosition(newPosition); nsTableFrame::RePositionViews(aKidFrame); aKidFrame->InvalidateFrameSubtree(); @@ -927,7 +931,7 @@ nsTableRowGroupFrame::SplitSpanningCells(nsPresContext& aPresContext, for (nsTableRowFrame* row = &aFirstRow; !wasLast; row = row->GetNextRow()) { wasLast = (row == &aLastRow); int32_t rowIndex = row->GetRowIndex(); - nsPoint rowPos = row->GetPosition(); + nsPoint rowPos = row->GetNormalPosition(); // Iterate the cells looking for those that have rowspan > 1 for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) { int32_t rowSpan = aTable.GetEffectiveRowSpan(rowIndex, *cell); @@ -942,7 +946,7 @@ nsTableRowGroupFrame::SplitSpanningCells(nsPresContext& aPresContext, NS_ASSERTION(cellAvailHeight >= 0, "No space for cell?"); bool isTopOfPage = (row == &aFirstRow) && aFirstRowIsTopOfPage; - nsRect rowRect = row->GetRect(); + nsRect rowRect = row->GetNormalRect(); nsSize rowAvailSize(aReflowState.AvailableWidth(), std::max(aReflowState.AvailableHeight() - rowRect.y, 0)); @@ -992,7 +996,7 @@ nsTableRowGroupFrame::SplitSpanningCells(nsPresContext& aPresContext, } } if (!haveRowSpan) { - aDesiredHeight = aLastRow.GetRect().YMost(); + aDesiredHeight = aLastRow.GetNormalRect().YMost(); } } @@ -1073,7 +1077,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsPresContext* aPresContext, for (nsTableRowFrame* rowFrame = firstRowThisPage; rowFrame; rowFrame = rowFrame->GetNextRow()) { bool rowIsOnPage = true; nscoord cellSpacingY = aTableFrame->GetCellSpacingY(rowFrame->GetRowIndex()); - nsRect rowRect = rowFrame->GetRect(); + nsRect rowRect = rowFrame->GetNormalRect(); // See if the row fits on this page if (rowRect.YMost() > availHeight) { nsTableRowFrame* contRow = nullptr; @@ -1179,7 +1183,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsPresContext* aPresContext, break; } if (prevRowFrame) { - spanningRowBottom = prevRowFrame->GetRect().YMost(); + spanningRowBottom = prevRowFrame->GetNormalRect().YMost(); lastRowThisPage = prevRowFrame; isTopOfPage = (lastRowThisPage == firstRowThisPage) && aReflowState.mFlags.mIsTopOfPage; aStatus = NS_FRAME_NOT_COMPLETE; @@ -1216,7 +1220,7 @@ nsTableRowGroupFrame::SplitRowGroup(nsPresContext* aPresContext, // Try to put firstTruncateRow on the next page nsTableRowFrame* rowBefore = ::GetRowBefore(*firstRowThisPage, *firstTruncatedRow); nscoord oldSpanningRowBottom = spanningRowBottom; - spanningRowBottom = rowBefore->GetRect().YMost(); + spanningRowBottom = rowBefore->GetNormalRect().YMost(); UndoContinuedRow(aPresContext, contRow); contRow = nullptr; @@ -1895,12 +1899,12 @@ nsTableRowGroupFrame::GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove) // encountering a row whose overflowArea.YMost() is <= aY but which has // a row above it containing cell(s) that span to include aY. while (cursorIndex > 0 && - cursorFrame->GetRect().YMost() + property->mOverflowBelow > aY) { + cursorFrame->GetNormalRect().YMost() + property->mOverflowBelow > aY) { --cursorIndex; cursorFrame = property->mFrames[cursorIndex]; } while (cursorIndex + 1 < frameCount && - cursorFrame->GetRect().YMost() + property->mOverflowBelow <= aY) { + cursorFrame->GetNormalRect().YMost() + property->mOverflowBelow <= aY) { ++cursorIndex; cursorFrame = property->mFrames[cursorIndex]; } @@ -1913,7 +1917,18 @@ nsTableRowGroupFrame::GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove) bool nsTableRowGroupFrame::FrameCursorData::AppendFrame(nsIFrame* aFrame) { - nsRect overflowRect = aFrame->GetVisualOverflowRect(); + // Relative positioning can cause table parts to move, but we will still paint + // the backgrounds for the parts under them at their 'normal' position. That + // means that we must consider the overflow rects at both positions. For + // example, if we use relative positioning to move a row-spanning cell, we + // will still paint the row background for that cell at its normal position, + // which will overflow the row. + // XXX(seth): This probably isn't correct in the presence of transforms. + nsRect positionedOverflowRect = aFrame->GetVisualOverflowRect(); + nsPoint positionedToNormal = aFrame->GetNormalPosition() - aFrame->GetPosition(); + nsRect normalOverflowRect = positionedOverflowRect + positionedToNormal; + + nsRect overflowRect = positionedOverflowRect.Union(normalOverflowRect); if (overflowRect.IsEmpty()) return true; nscoord overflowAbove = -overflowRect.y; diff --git a/layout/tables/nsTableRowGroupFrame.h b/layout/tables/nsTableRowGroupFrame.h index 07a5704fc282..dba599e18c2e 100644 --- a/layout/tables/nsTableRowGroupFrame.h +++ b/layout/tables/nsTableRowGroupFrame.h @@ -337,6 +337,7 @@ protected: void PlaceChild(nsPresContext* aPresContext, nsRowGroupReflowState& aReflowState, nsIFrame* aKidFrame, + nsPoint aKidPosition, nsHTMLReflowMetrics& aDesiredSize, const nsRect& aOriginalKidRect, const nsRect& aOriginalKidVisualOverflow); From 6a831f1e580be4d99196b6b4c242c95839f3303b Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Tue, 19 Aug 2014 18:24:58 -0700 Subject: [PATCH 06/17] Bug 35168 (Part 3) - Add tests for table part relative positioning. r=dbaron --- .../reftests/position-relative/reftest.list | 8 + .../table-collapse-1-ref.html | 180 ++++++++++++++++++ .../position-relative/table-collapse-1.html | 80 ++++++++ .../table-collapse-2-ref.html | 180 ++++++++++++++++++ .../position-relative/table-collapse-2.html | 82 ++++++++ .../table-collapse-3-ref.html | 180 ++++++++++++++++++ .../position-relative/table-collapse-3.html | 80 ++++++++ .../table-collapse-4-ref.html | 180 ++++++++++++++++++ .../position-relative/table-collapse-4.html | 82 ++++++++ .../table-separate-1-ref.html | 179 +++++++++++++++++ .../position-relative/table-separate-1.html | 80 ++++++++ .../table-separate-2-ref.html | 179 +++++++++++++++++ .../position-relative/table-separate-2.html | 82 ++++++++ .../table-separate-3-ref.html | 179 +++++++++++++++++ .../position-relative/table-separate-3.html | 80 ++++++++ .../table-separate-4-ref.html | 179 +++++++++++++++++ .../position-relative/table-separate-4.html | 82 ++++++++ layout/reftests/reftest.list | 1 + 18 files changed, 2093 insertions(+) create mode 100644 layout/reftests/position-relative/reftest.list create mode 100644 layout/reftests/position-relative/table-collapse-1-ref.html create mode 100644 layout/reftests/position-relative/table-collapse-1.html create mode 100644 layout/reftests/position-relative/table-collapse-2-ref.html create mode 100644 layout/reftests/position-relative/table-collapse-2.html create mode 100644 layout/reftests/position-relative/table-collapse-3-ref.html create mode 100644 layout/reftests/position-relative/table-collapse-3.html create mode 100644 layout/reftests/position-relative/table-collapse-4-ref.html create mode 100644 layout/reftests/position-relative/table-collapse-4.html create mode 100644 layout/reftests/position-relative/table-separate-1-ref.html create mode 100644 layout/reftests/position-relative/table-separate-1.html create mode 100644 layout/reftests/position-relative/table-separate-2-ref.html create mode 100644 layout/reftests/position-relative/table-separate-2.html create mode 100644 layout/reftests/position-relative/table-separate-3-ref.html create mode 100644 layout/reftests/position-relative/table-separate-3.html create mode 100644 layout/reftests/position-relative/table-separate-4-ref.html create mode 100644 layout/reftests/position-relative/table-separate-4.html diff --git a/layout/reftests/position-relative/reftest.list b/layout/reftests/position-relative/reftest.list new file mode 100644 index 000000000000..e317882d1f97 --- /dev/null +++ b/layout/reftests/position-relative/reftest.list @@ -0,0 +1,8 @@ +== table-collapse-1.html table-collapse-1-ref.html +== table-collapse-2.html table-collapse-2-ref.html +== table-collapse-3.html table-collapse-3-ref.html +== table-collapse-4.html table-collapse-4-ref.html +== table-separate-1.html table-separate-1-ref.html +== table-separate-2.html table-separate-2-ref.html +== table-separate-3.html table-separate-3-ref.html +== table-separate-4.html table-separate-4-ref.html diff --git a/layout/reftests/position-relative/table-collapse-1-ref.html b/layout/reftests/position-relative/table-collapse-1-ref.html new file mode 100644 index 000000000000..e2f9edd47291 --- /dev/null +++ b/layout/reftests/position-relative/table-collapse-1-ref.html @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
 
XXX
XXX 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-collapse-1.html b/layout/reftests/position-relative/table-collapse-1.html new file mode 100644 index 000000000000..80ee9fe2207b --- /dev/null +++ b/layout/reftests/position-relative/table-collapse-1.html @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-collapse-2-ref.html b/layout/reftests/position-relative/table-collapse-2-ref.html new file mode 100644 index 000000000000..f99d2ef74f02 --- /dev/null +++ b/layout/reftests/position-relative/table-collapse-2-ref.html @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
 
XXX
XXX 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-collapse-2.html b/layout/reftests/position-relative/table-collapse-2.html new file mode 100644 index 000000000000..c1c96d830194 --- /dev/null +++ b/layout/reftests/position-relative/table-collapse-2.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-collapse-3-ref.html b/layout/reftests/position-relative/table-collapse-3-ref.html new file mode 100644 index 000000000000..e2c6d43b468a --- /dev/null +++ b/layout/reftests/position-relative/table-collapse-3-ref.html @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
 
XXX
XXX 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-collapse-3.html b/layout/reftests/position-relative/table-collapse-3.html new file mode 100644 index 000000000000..00d8539b022e --- /dev/null +++ b/layout/reftests/position-relative/table-collapse-3.html @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-collapse-4-ref.html b/layout/reftests/position-relative/table-collapse-4-ref.html new file mode 100644 index 000000000000..b64b332147ea --- /dev/null +++ b/layout/reftests/position-relative/table-collapse-4-ref.html @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
 
XXX
XXX 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-collapse-4.html b/layout/reftests/position-relative/table-collapse-4.html new file mode 100644 index 000000000000..fc7b48de261e --- /dev/null +++ b/layout/reftests/position-relative/table-collapse-4.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-separate-1-ref.html b/layout/reftests/position-relative/table-separate-1-ref.html new file mode 100644 index 000000000000..b46232714dec --- /dev/null +++ b/layout/reftests/position-relative/table-separate-1-ref.html @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
 
XXX
XXX 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-separate-1.html b/layout/reftests/position-relative/table-separate-1.html new file mode 100644 index 000000000000..d97fa15d8a7e --- /dev/null +++ b/layout/reftests/position-relative/table-separate-1.html @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-separate-2-ref.html b/layout/reftests/position-relative/table-separate-2-ref.html new file mode 100644 index 000000000000..90d7c6884b75 --- /dev/null +++ b/layout/reftests/position-relative/table-separate-2-ref.html @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
 
XXX
XXX 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-separate-2.html b/layout/reftests/position-relative/table-separate-2.html new file mode 100644 index 000000000000..583771328c35 --- /dev/null +++ b/layout/reftests/position-relative/table-separate-2.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-separate-3-ref.html b/layout/reftests/position-relative/table-separate-3-ref.html new file mode 100644 index 000000000000..52765315178d --- /dev/null +++ b/layout/reftests/position-relative/table-separate-3-ref.html @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
 
XXX
XXX 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-separate-3.html b/layout/reftests/position-relative/table-separate-3.html new file mode 100644 index 000000000000..a739fb771287 --- /dev/null +++ b/layout/reftests/position-relative/table-separate-3.html @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-separate-4-ref.html b/layout/reftests/position-relative/table-separate-4-ref.html new file mode 100644 index 000000000000..b5cfd2783fd8 --- /dev/null +++ b/layout/reftests/position-relative/table-separate-4-ref.html @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
 
XXX
XXX 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/position-relative/table-separate-4.html b/layout/reftests/position-relative/table-separate-4.html new file mode 100644 index 000000000000..9634117b7467 --- /dev/null +++ b/layout/reftests/position-relative/table-separate-4.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
XXXYYY
XXXYYY
XXXYYY
XXX
XXX
XXXYYY
+ diff --git a/layout/reftests/reftest.list b/layout/reftests/reftest.list index c8e4497c05b4..e54f8ef4df87 100644 --- a/layout/reftests/reftest.list +++ b/layout/reftests/reftest.list @@ -17,6 +17,7 @@ include w3c-css/received/reftest.list # relative and absolute positioning include abs-pos/reftest.list +include position-relative/reftest.list include async-scrolling/reftest.list From 7f507df2470235f0f75568151b05c5e532ac50dc Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 22 Dec 2014 12:54:05 -0500 Subject: [PATCH 07/17] Bug 1114662 - add --enable-thread-sanitizer configure option; r=glandium Like --enable-{address,memory}-sanitizer, this doesn't add the appropriate -fsanitize=FOO flags; it merely sets internal defines and the LLVM_SYMBOLIZER variable. --- configure.in | 14 ++++++++++++++ js/src/configure.in | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/configure.in b/configure.in index 1ffa1c63983b..4edf7c532fb5 100644 --- a/configure.in +++ b/configure.in @@ -1300,6 +1300,20 @@ if test -n "$MOZ_MSAN"; then fi AC_SUBST(MOZ_MSAN) +dnl ======================================================== +dnl = Use Thread Sanitizer +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(thread-sanitizer, +[ --enable-thread-sanitizer Enable Thread Sanitizer (default=no)], + MOZ_TSAN=1, + MOZ_TSAN= ) +if test -n "$MOZ_TSAN"; then + MOZ_LLVM_HACKS=1 + AC_DEFINE(MOZ_TSAN) + MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer) +fi +AC_SUBST(MOZ_TSAN) + # The LLVM symbolizer is used by all sanitizers AC_SUBST(LLVM_SYMBOLIZER) diff --git a/js/src/configure.in b/js/src/configure.in index 39b9d0de43e0..b6877824aa95 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -1078,6 +1078,20 @@ if test -n "$MOZ_MSAN"; then fi AC_SUBST(MOZ_MSAN) +dnl ======================================================== +dnl = Use Thread Sanitizer +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(thread-sanitizer, +[ --enable-thread-sanitizer Enable Thread Sanitizer (default=no)], + MOZ_TSAN=1, + MOZ_TSAN= ) +if test -n "$MOZ_TSAN"; then + MOZ_LLVM_HACKS=1 + AC_DEFINE(MOZ_TSAN) + MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer) +fi +AC_SUBST(MOZ_TSAN) + # The LLVM symbolizer is used by all sanitizers AC_SUBST(LLVM_SYMBOLIZER) From 6da48b0d6c1c4ced3491ca69d46b4f42afce14b0 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 22 Dec 2014 13:46:14 -0500 Subject: [PATCH 08/17] Bug 1114684 - inform mozinfo about the MOZ_TSAN build configuration; r=ahal Various bits of the test harnesses key off of mozinfo.info.get('asan'); we will need a similar switch for finding out whether this build supports tsan. --- python/mozbuild/mozbuild/mozinfo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/mozbuild/mozbuild/mozinfo.py b/python/mozbuild/mozbuild/mozinfo.py index fd2b85fdbe96..9e874781938b 100755 --- a/python/mozbuild/mozbuild/mozinfo.py +++ b/python/mozbuild/mozbuild/mozinfo.py @@ -82,6 +82,7 @@ def build_dict(config, env=os.environ): d['datareporting'] = bool(substs.get('MOZ_DATA_REPORTING')) d['healthreport'] = substs.get('MOZ_SERVICES_HEALTHREPORT') == '1' d['asan'] = substs.get('MOZ_ASAN') == '1' + d['tsan'] = substs.get('MOZ_TSAN') == '1' d['tests_enabled'] = substs.get('ENABLE_TESTS') == "1" d['bin_suffix'] = substs.get('BIN_SUFFIX', '') From 8f1cfd85fd374b932d8ede5560ca94ba1d16dd46 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 22 Dec 2014 16:00:34 -0500 Subject: [PATCH 09/17] Bug 1114745 - remove dead IS_ASAN defines from automation-build.mk; r=ted Nothing uses IS_ASAN, likely because all relevant uses have been ported over to mozinfo. --- build/automation-build.mk | 6 ------ 1 file changed, 6 deletions(-) diff --git a/build/automation-build.mk b/build/automation-build.mk index 94b88b40fda0..ad71909fc656 100644 --- a/build/automation-build.mk +++ b/build/automation-build.mk @@ -54,12 +54,6 @@ else AUTOMATION_PPARGS += -DCRASHREPORTER=0 endif -ifdef MOZ_ASAN -AUTOMATION_PPARGS += -DIS_ASAN=1 -else -AUTOMATION_PPARGS += -DIS_ASAN=0 -endif - automation.py: $(MOZILLA_DIR)/build/automation.py.in $(MOZILLA_DIR)/build/automation-build.mk $(call py_action,preprocessor, \ $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< -o $@) From 91cb86ec1b5a8428d7256763dfae2c07d6f61c16 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Tue, 23 Dec 2014 16:32:03 +0100 Subject: [PATCH 10/17] Bug 1114566 - matchCallee: Check if both functions have a script before comparing them. r=shu --- js/src/jit-test/tests/ion/recover-lambdas-bug1114566.js | 2 ++ js/src/vm/Stack.cpp | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/ion/recover-lambdas-bug1114566.js diff --git a/js/src/jit-test/tests/ion/recover-lambdas-bug1114566.js b/js/src/jit-test/tests/ion/recover-lambdas-bug1114566.js new file mode 100644 index 000000000000..ada8e59f38c5 --- /dev/null +++ b/js/src/jit-test/tests/ion/recover-lambdas-bug1114566.js @@ -0,0 +1,2 @@ + +(new Function("return (function o() {}).caller;"))(); diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 7b57984d8839..1a735d64e7b8 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -1124,8 +1124,12 @@ FrameIter::matchCallee(JSContext *cx, HandleFunction fun) const // expect both functions to have the same JSScript. If so, and if they are // different, then they cannot be equal. bool useSameScript = CloneFunctionObjectUseSameScript(fun->compartment(), currentCallee); - if (useSameScript && currentCallee->nonLazyScript() != fun->nonLazyScript()) + if (useSameScript && + (currentCallee->hasScript() != fun->hasScript() || + currentCallee->nonLazyScript() != fun->nonLazyScript())) + { return false; + } // If none of the previous filters worked, then take the risk of // invalidating the frame to identify the JSFunction. From 0e7074b2bd880acb7a7f9a07de8fe8899b614c9a Mon Sep 17 00:00:00 2001 From: Yan Gouts Date: Tue, 23 Dec 2014 10:35:58 -0500 Subject: [PATCH 11/17] Bug 1113774 - Transitioned FrameMetric mDisplayPort accesses to Get/Set method calls. r=kats --- gfx/layers/FrameMetrics.h | 38 ++++++++++++------- gfx/layers/LayersLogging.cpp | 2 +- gfx/layers/apz/src/AsyncPanZoomController.cpp | 12 +++--- gfx/layers/client/ClientLayerManager.cpp | 2 +- gfx/layers/client/ClientTiledPaintedLayer.cpp | 4 +- gfx/layers/client/TiledContentClient.cpp | 10 ++--- .../composite/AsyncCompositionManager.cpp | 4 +- .../composite/LayerManagerComposite.cpp | 6 +-- .../gtest/TestAsyncPanZoomController.cpp | 4 +- layout/base/nsDisplayList.cpp | 4 +- 10 files changed, 48 insertions(+), 38 deletions(-) diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h index ac5c0d6c5c55..bf677ca14d10 100644 --- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -40,10 +40,10 @@ public: FrameMetrics() : mCompositionBounds(0, 0, 0, 0) - , mDisplayPort(0, 0, 0, 0) , mCriticalDisplayPort(0, 0, 0, 0) , mScrollableRect(0, 0, 0, 0) , mPresShellResolution(1) + , mDisplayPort(0, 0, 0, 0) , mCumulativeResolution(1) , mDevPixelsPerCSSPixel(1) , mMayHaveTouchListeners(false) @@ -256,19 +256,6 @@ public: // space, so each is explained separately. // - // The area of a frame's contents that has been painted, relative to - // mCompositionBounds. - // - // Note that this is structured in such a way that it doesn't depend on the - // method layout uses to scroll content. - // - // May be larger or smaller than |mScrollableRect|. - // - // To pre-render a margin of 100 CSS pixels around the window, - // { x = -100, y = - 100, - // width = window.innerWidth + 200, height = window.innerHeight + 200 } - CSSRect mDisplayPort; - // If non-empty, the area of a frame's contents that is considered critical // to paint. Area outside of this area (i.e. area inside mDisplayPort, but // outside of mCriticalDisplayPort) is considered low-priority, and may be @@ -304,6 +291,16 @@ public: float mPresShellResolution; public: + void SetDisplayPort(const CSSRect& aDisplayPort) + { + mDisplayPort = aDisplayPort; + } + + CSSRect GetDisplayPort() const + { + return mDisplayPort; + } + void SetCumulativeResolution(const LayoutDeviceToLayerScale& aCumulativeResolution) { mCumulativeResolution = aCumulativeResolution; @@ -532,6 +529,19 @@ public: } private: + // The area of a frame's contents that has been painted, relative to + // mCompositionBounds. + // + // Note that this is structured in such a way that it doesn't depend on the + // method layout uses to scroll content. + // + // May be larger or smaller than |mScrollableRect|. + // + // To pre-render a margin of 100 CSS pixels around the window, + // { x = -100, y = - 100, + // width = window.innerWidth + 200, height = window.innerHeight + 200 } + CSSRect mDisplayPort; + // The cumulative resolution that the current frame has been painted at. // This is the product of the pres-shell resolutions of the document // containing this scroll frame and its ancestors, and any css-driven diff --git a/gfx/layers/LayersLogging.cpp b/gfx/layers/LayersLogging.cpp index b98b1ec8ed25..0379df187cda 100644 --- a/gfx/layers/LayersLogging.cpp +++ b/gfx/layers/LayersLogging.cpp @@ -175,7 +175,7 @@ AppendToString(std::stringstream& aStream, const FrameMetrics& m, if (m.GetDoSmoothScroll()) { AppendToString(aStream, m.GetSmoothScrollOffset(), "] [ss="); } - AppendToString(aStream, m.mDisplayPort, "] [dp="); + AppendToString(aStream, m.GetDisplayPort(), "] [dp="); AppendToString(aStream, m.mCriticalDisplayPort, "] [cdp="); AppendToString(aStream, m.GetBackgroundColor(), "] [color="); if (!detailed) { diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 42a0f3ad7f55..14d2f0ab197c 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -2620,12 +2620,12 @@ ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() const { // If checkerboarding has been disallowed, clamp the scroll position to stay // within rendered content. if (!gfxPrefs::APZAllowCheckerboarding() && - !mLastContentPaintMetrics.mDisplayPort.IsEmpty()) { + !mLastContentPaintMetrics.GetDisplayPort().IsEmpty()) { CSSSize compositedSize = mLastContentPaintMetrics.CalculateCompositedSizeInCssPixels(); CSSPoint maxScrollOffset = lastPaintScrollOffset + - CSSPoint(mLastContentPaintMetrics.mDisplayPort.XMost() - compositedSize.width, - mLastContentPaintMetrics.mDisplayPort.YMost() - compositedSize.height); - CSSPoint minScrollOffset = lastPaintScrollOffset + mLastContentPaintMetrics.mDisplayPort.TopLeft(); + CSSPoint(mLastContentPaintMetrics.GetDisplayPort().XMost() - compositedSize.width, + mLastContentPaintMetrics.GetDisplayPort().YMost() - compositedSize.height); + CSSPoint minScrollOffset = lastPaintScrollOffset + mLastContentPaintMetrics.GetDisplayPort().TopLeft(); if (minScrollOffset.x < maxScrollOffset.x) { currentScrollOffset.x = clamped(currentScrollOffset.x, minScrollOffset.x, maxScrollOffset.x); @@ -2681,7 +2681,7 @@ bool AsyncPanZoomController::IsCurrentlyCheckerboarding() const { } CSSPoint currentScrollOffset = mFrameMetrics.GetScrollOffset() + mTestAsyncScrollOffset; - CSSRect painted = mLastContentPaintMetrics.mDisplayPort + mLastContentPaintMetrics.GetScrollOffset(); + CSSRect painted = mLastContentPaintMetrics.GetDisplayPort() + mLastContentPaintMetrics.GetScrollOffset(); painted.Inflate(CSSMargin::FromAppUnits(nsMargin(1, 1, 1, 1))); // fuzz for rounding error CSSRect visible = CSSRect(currentScrollOffset, mFrameMetrics.CalculateCompositedSizeInCssPixels()); return !painted.Contains(visible); @@ -2702,7 +2702,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri LogRendertraceRect(GetGuid(), "page", "brown", aLayerMetrics.mScrollableRect); LogRendertraceRect(GetGuid(), "painted displayport", "lightgreen", - aLayerMetrics.mDisplayPort + aLayerMetrics.GetScrollOffset()); + aLayerMetrics.GetDisplayPort() + aLayerMetrics.GetScrollOffset()); if (!aLayerMetrics.mCriticalDisplayPort.IsEmpty()) { LogRendertraceRect(GetGuid(), "painted critical displayport", "darkgreen", aLayerMetrics.mCriticalDisplayPort + aLayerMetrics.GetScrollOffset()); diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index 3ea4ce5041eb..d266e34adade 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -753,7 +753,7 @@ ClientLayerManager::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, CSSToLayerScale paintScale = aMetrics.LayersPixelsPerCSSPixel(); const CSSRect& metricsDisplayPort = (aDrawingCritical && !aMetrics.mCriticalDisplayPort.IsEmpty()) ? - aMetrics.mCriticalDisplayPort : aMetrics.mDisplayPort; + aMetrics.mCriticalDisplayPort : aMetrics.GetDisplayPort(); LayerRect displayPort = (metricsDisplayPort + aMetrics.GetScrollOffset()) * paintScale; ParentLayerPoint scrollOffset; diff --git a/gfx/layers/client/ClientTiledPaintedLayer.cpp b/gfx/layers/client/ClientTiledPaintedLayer.cpp index 5452d8e81397..d3190b209866 100644 --- a/gfx/layers/client/ClientTiledPaintedLayer.cpp +++ b/gfx/layers/client/ClientTiledPaintedLayer.cpp @@ -91,7 +91,7 @@ ClientTiledPaintedLayer::GetAncestorLayers(LayerMetricsWrapper* aOutScrollAncest if (!scrollAncestor && metrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID) { scrollAncestor = ancestor; } - if (!metrics.mDisplayPort.IsEmpty()) { + if (!metrics.GetDisplayPort().IsEmpty()) { displayPortAncestor = ancestor; // Any layer that has a displayport must be scrollable, so we can break // here. @@ -191,7 +191,7 @@ ClientTiledPaintedLayer::UseFastPath() || gfxPrefs::UseLowPrecisionBuffer() || !parentMetrics.mCriticalDisplayPort.IsEmpty(); bool isFixed = GetIsFixedPosition() || GetParent()->GetIsFixedPosition(); - return !multipleTransactionsNeeded || isFixed || parentMetrics.mDisplayPort.IsEmpty(); + return !multipleTransactionsNeeded || isFixed || parentMetrics.GetDisplayPort().IsEmpty(); } bool diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index c893cbb9bd6c..5d49a54f0707 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -213,10 +213,10 @@ SharedFrameMetricsHelper::UpdateFromCompositorFrameMetrics( // an endless updating cycle. if (fabsf(contentMetrics.GetScrollOffset().x - compositorMetrics.GetScrollOffset().x) <= 2 && fabsf(contentMetrics.GetScrollOffset().y - compositorMetrics.GetScrollOffset().y) <= 2 && - fabsf(contentMetrics.mDisplayPort.x - compositorMetrics.mDisplayPort.x) <= 2 && - fabsf(contentMetrics.mDisplayPort.y - compositorMetrics.mDisplayPort.y) <= 2 && - fabsf(contentMetrics.mDisplayPort.width - compositorMetrics.mDisplayPort.width) <= 2 && - fabsf(contentMetrics.mDisplayPort.height - compositorMetrics.mDisplayPort.height) <= 2) { + fabsf(contentMetrics.GetDisplayPort().x - compositorMetrics.GetDisplayPort().x) <= 2 && + fabsf(contentMetrics.GetDisplayPort().y - compositorMetrics.GetDisplayPort().y) <= 2 && + fabsf(contentMetrics.GetDisplayPort().width - compositorMetrics.GetDisplayPort().width) <= 2 && + fabsf(contentMetrics.GetDisplayPort().height - compositorMetrics.GetDisplayPort().height) <= 2) { return false; } @@ -258,7 +258,7 @@ SharedFrameMetricsHelper::AboutToCheckerboard(const FrameMetrics& aContentMetric // This process can introduce some rounding error, so we inflate the rect by one app unit // to account for that. CSSRect painted = (aContentMetrics.mCriticalDisplayPort.IsEmpty() - ? aContentMetrics.mDisplayPort + ? aContentMetrics.GetDisplayPort() : aContentMetrics.mCriticalDisplayPort) + aContentMetrics.GetScrollOffset(); painted.Inflate(CSSMargin::FromAppUnits(nsMargin(1, 1, 1, 1))); diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index e81ee0d41e6c..263aa36437cc 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -605,7 +605,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer) const FrameMetrics& metrics = aLayer->GetFrameMetrics(i); CSSToLayerScale paintScale = metrics.LayersPixelsPerCSSPixel(); CSSRect displayPort(metrics.mCriticalDisplayPort.IsEmpty() ? - metrics.mDisplayPort : metrics.mCriticalDisplayPort); + metrics.GetDisplayPort() : metrics.mCriticalDisplayPort); ScreenPoint offset(0, 0); // XXX this call to SyncFrameMetrics is not currently being used. It will be cleaned // up as part of bug 776030 or one of its dependencies. @@ -860,7 +860,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer) // Calculate the absolute display port to send to Java LayerIntRect displayPort = RoundedToInt( (metrics.mCriticalDisplayPort.IsEmpty() - ? metrics.mDisplayPort + ? metrics.GetDisplayPort() : metrics.mCriticalDisplayPort ) * geckoZoom); displayPort += scrollOffsetLayerPixels; diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index 634a8a272099..eeed50adab1e 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -935,13 +935,13 @@ LayerManagerComposite::ComputeRenderIntegrity() } // Work out how much of the display-port covers the screen - if (!metrics.mDisplayPort.IsEmpty()) { + if (!metrics.GetDisplayPort().IsEmpty()) { if (hasLowPrecision) { lowPrecisionMultiplier = - GetDisplayportCoverage(metrics.mDisplayPort, transform, screenRect); + GetDisplayportCoverage(metrics.GetDisplayPort(), transform, screenRect); } else { lowPrecisionMultiplier = highPrecisionMultiplier = - GetDisplayportCoverage(metrics.mDisplayPort, transform, screenRect); + GetDisplayportCoverage(metrics.GetDisplayPort(), transform, screenRect); } } } diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp index ebb193e8130a..f171e8a693e0 100644 --- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp +++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp @@ -223,7 +223,7 @@ TestFrameMetrics() { FrameMetrics fm; - fm.mDisplayPort = CSSRect(0, 0, 10, 10); + fm.SetDisplayPort(CSSRect(0, 0, 10, 10)); fm.mCompositionBounds = ParentLayerRect(0, 0, 10, 10); fm.mCriticalDisplayPort = CSSRect(0, 0, 10, 10); fm.mScrollableRect = CSSRect(0, 0, 100, 100); @@ -816,7 +816,7 @@ TEST_F(APZCBasicTester, ComplexTransform) { FrameMetrics metrics; metrics.mCompositionBounds = ParentLayerRect(0, 0, 24, 24); - metrics.mDisplayPort = CSSRect(-1, -1, 6, 6); + metrics.SetDisplayPort(CSSRect(-1, -1, 6, 6)); metrics.SetScrollOffset(CSSPoint(10, 10)); metrics.mScrollableRect = CSSRect(0, 0, 50, 50); metrics.SetCumulativeResolution(LayoutDeviceToLayerScale(2)); diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 6a4b2a12859f..a6090fce8c8b 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -716,9 +716,9 @@ nsDisplayScrollLayer::ComputeFrameMetrics(nsIFrame* aForFrame, } nsRect dp; if (nsLayoutUtils::GetDisplayPort(content, &dp)) { - metrics.mDisplayPort = CSSRect::FromAppUnits(dp); + metrics.SetDisplayPort(CSSRect::FromAppUnits(dp)); nsLayoutUtils::LogTestDataForPaint(aLayer->Manager(), scrollId, "displayport", - metrics.mDisplayPort); + metrics.GetDisplayPort()); } if (nsLayoutUtils::GetCriticalDisplayPort(content, &dp)) { metrics.mCriticalDisplayPort = CSSRect::FromAppUnits(dp); From 40f59091b1dee5a0b6b29f93a2192ed8952bf32b Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 23 Dec 2014 10:40:57 -0500 Subject: [PATCH 12/17] Backout 4aa280efb6ea (bug 1114745) for various test bustage --- build/automation-build.mk | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build/automation-build.mk b/build/automation-build.mk index ad71909fc656..94b88b40fda0 100644 --- a/build/automation-build.mk +++ b/build/automation-build.mk @@ -54,6 +54,12 @@ else AUTOMATION_PPARGS += -DCRASHREPORTER=0 endif +ifdef MOZ_ASAN +AUTOMATION_PPARGS += -DIS_ASAN=1 +else +AUTOMATION_PPARGS += -DIS_ASAN=0 +endif + automation.py: $(MOZILLA_DIR)/build/automation.py.in $(MOZILLA_DIR)/build/automation-build.mk $(call py_action,preprocessor, \ $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< -o $@) From 3c6462cb13bec5643e3cd9fb28249d10a83df153 Mon Sep 17 00:00:00 2001 From: Milan Sreckovic Date: Fri, 19 Dec 2014 16:06:15 -0500 Subject: [PATCH 13/17] Bug 1095510 - See if ClearRect has weird data. r=jmuizelaar --- gfx/2d/DrawTargetCairo.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gfx/2d/DrawTargetCairo.cpp b/gfx/2d/DrawTargetCairo.cpp index 61dc9da1616d..5c0ec648524d 100644 --- a/gfx/2d/DrawTargetCairo.cpp +++ b/gfx/2d/DrawTargetCairo.cpp @@ -1046,6 +1046,12 @@ DrawTargetCairo::ClearRect(const Rect& aRect) { AutoPrepareForDrawing prep(this, mContext); + if (!mContext || aRect.Width() <= 0 || aRect.Height() <= 0 || + !IsFinite(aRect.X()) || !IsFinite(aRect.Width()) || + !IsFinite(aRect.Y()) || !IsFinite(aRect.Height())) { + gfxCriticalError(CriticalLog::DefaultOptions(false)) << "ClearRect with invalid argument " << gfx::hexa(mContext) << " with " << aRect.Width() << "x" << aRect.Height() << " [" << aRect.X() << ", " << aRect.Y() << "]"; + } + cairo_set_antialias(mContext, CAIRO_ANTIALIAS_NONE); cairo_new_path(mContext); cairo_set_operator(mContext, CAIRO_OPERATOR_CLEAR); From e022c4f6c6e697d5d909dad7e728d9eae1bee740 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Sat, 30 Aug 2014 13:56:23 +0100 Subject: [PATCH 14/17] Bug 983985 - Reftests for hexbox in fake-italic text. r=bas --- layout/reftests/bugs/983985-1-ref.html | 19 +++++++++++++++++ layout/reftests/bugs/983985-1.html | 19 +++++++++++++++++ layout/reftests/bugs/983985-2-ref.html | 28 ++++++++++++++++++++++++++ layout/reftests/bugs/983985-2.html | 28 ++++++++++++++++++++++++++ layout/reftests/bugs/reftest.list | 2 ++ 5 files changed, 96 insertions(+) create mode 100644 layout/reftests/bugs/983985-1-ref.html create mode 100644 layout/reftests/bugs/983985-1.html create mode 100644 layout/reftests/bugs/983985-2-ref.html create mode 100644 layout/reftests/bugs/983985-2.html diff --git a/layout/reftests/bugs/983985-1-ref.html b/layout/reftests/bugs/983985-1-ref.html new file mode 100644 index 000000000000..4a8d7e94d757 --- /dev/null +++ b/layout/reftests/bugs/983985-1-ref.html @@ -0,0 +1,19 @@ + + + + +Bug 983985 + + + +hello ԰ world + + diff --git a/layout/reftests/bugs/983985-1.html b/layout/reftests/bugs/983985-1.html new file mode 100644 index 000000000000..44b7837159cb --- /dev/null +++ b/layout/reftests/bugs/983985-1.html @@ -0,0 +1,19 @@ + + + + +Bug 983985 + + + +hello ԰ world + + diff --git a/layout/reftests/bugs/983985-2-ref.html b/layout/reftests/bugs/983985-2-ref.html new file mode 100644 index 000000000000..732bd1c8170d --- /dev/null +++ b/layout/reftests/bugs/983985-2-ref.html @@ -0,0 +1,28 @@ + + + + +Bug 983985 + + + +
+
+hello ԰ world +
+
+ + diff --git a/layout/reftests/bugs/983985-2.html b/layout/reftests/bugs/983985-2.html new file mode 100644 index 000000000000..39a88428f02e --- /dev/null +++ b/layout/reftests/bugs/983985-2.html @@ -0,0 +1,28 @@ + + + + +Bug 983985 + + + +
+
+hello ԰ world +
+
+ + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 68c79c360090..5676637079b2 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1810,6 +1810,8 @@ skip-if(Android) == 966510-2.html 966510-2-ref.html # same as above == 983084-2.html 983084-2-ref.html == 983084-3.html 983084-1-ref.html == 983691-1.html 983691-ref.html +HTTP(..) == 983985-1.html 983985-1-ref.html +HTTP(..) == 983985-2.html 983985-2-ref.html == 985303-1a.html 985303-1-ref.html == 985303-1b.html 985303-1-ref.html == 987680-1.html 987680-1-ref.html From 22c6a4800b07431b89303353ce35b9e8b915e1f7 Mon Sep 17 00:00:00 2001 From: Guilherme Goncalves Date: Fri, 19 Dec 2014 09:15:00 -0500 Subject: [PATCH 15/17] Bug 899126 - Part 1: Implement bin_unused for jemalloc3. r=glandium --- memory/build/mozjemalloc_compat.c | 77 ++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/memory/build/mozjemalloc_compat.c b/memory/build/mozjemalloc_compat.c index 55b47243a20f..3647e86194c0 100644 --- a/memory/build/mozjemalloc_compat.c +++ b/memory/build/mozjemalloc_compat.c @@ -10,8 +10,11 @@ #include "mozmemory_wrap.h" #include "jemalloc_types.h" +#include "jemalloc/internal/jemalloc_internal_defs.h" // for JEMALLOC_HAS_ALLOCA_H #include "mozilla/Types.h" +#include + #if defined(MOZ_NATIVE_JEMALLOC) MOZ_IMPORT_API int @@ -47,6 +50,37 @@ je_(nallocx)(size_t size, int flags); je_(mallctlbymib)(mib, miblen, &v, &sz, NULL, 0); \ } while (0) +#define CTL_IJ_GET(n, v, i, j) do { \ + size_t mib[6]; \ + size_t miblen = sizeof(mib) / sizeof(mib[0]); \ + size_t sz = sizeof(v); \ + je_(mallctlnametomib)(n, mib, &miblen); \ + mib[2] = i; \ + mib[4] = j; \ + je_(mallctlbymib)(mib, miblen, &v, &sz, NULL, 0); \ +} while (0) + +/* + * VARIABLE_ARRAY is copied from + * memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal.h.in + */ +#if __STDC_VERSION__ < 199901L +# ifdef _MSC_VER +# include +# define alloca _alloca +# else +# ifdef JEMALLOC_HAS_ALLOCA_H +# include +# else +# include +# endif +# endif +# define VARIABLE_ARRAY(type, name, count) \ + type *name = alloca(sizeof(type) * (count)) +#else +# define VARIABLE_ARRAY(type, name, count) type name[(count)] +#endif + MOZ_MEMORY_API size_t malloc_good_size_impl(size_t size) { @@ -58,6 +92,46 @@ malloc_good_size_impl(size_t size) return je_(nallocx)(size, 0); } +static size_t +compute_bin_unused(unsigned int narenas) +{ + size_t bin_unused = 0; + + uint32_t nregs; // number of regions per run in the j-th bin + size_t reg_size; // size of regions served by the j-th bin + size_t curruns; // number of runs belonging to a bin + size_t curregs; // number of allocated regions in a bin + + unsigned int nbins; // number of bins per arena + unsigned int i, j; + + // narenas also counts uninitialized arenas, and initialized arenas + // are not guaranteed to be adjacent + VARIABLE_ARRAY(bool, initialized, narenas); + size_t isz = sizeof(initialized) / sizeof(initialized[0]); + + je_(mallctl)("arenas.initialized", initialized, &isz, NULL, 0); + CTL_GET("arenas.nbins", nbins); + + for (j = 0; j < nbins; j++) { + CTL_I_GET("arenas.bin.0.nregs", nregs, j); + CTL_I_GET("arenas.bin.0.size", reg_size, j); + + for (i = 0; i < narenas; i++) { + if (!initialized[i]) { + continue; + } + + CTL_IJ_GET("stats.arenas.0.bins.0.curruns", curruns, i, j); + CTL_IJ_GET("stats.arenas.0.bins.0.curregs", curregs, i, j); + + bin_unused += (nregs * curruns - curregs) * reg_size; + } + } + + return bin_unused; +} + MOZ_JEMALLOC_API void jemalloc_stats_impl(jemalloc_stats_t *stats) { @@ -90,7 +164,8 @@ jemalloc_stats_impl(jemalloc_stats_t *stats) // We could get this value out of base.c::base_pages, but that really should // be an upstream change, so don't worry about it for now. stats->bookkeeping = 0; - stats->bin_unused = 0; + + stats->bin_unused = compute_bin_unused(narenas); } MOZ_JEMALLOC_API void From 8e013fa5d0dd98abab34e03e89e13f78d02834d8 Mon Sep 17 00:00:00 2001 From: "Hallvord R. M. Steen" Date: Thu, 27 Nov 2014 10:23:51 +0100 Subject: [PATCH 16/17] Bug 1101873 - Remove the part of the 923971 patch that caused a new problem. r=enndeakin --- layout/xul/nsMenuBarFrame.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/layout/xul/nsMenuBarFrame.cpp b/layout/xul/nsMenuBarFrame.cpp index a0eabe5d9aa2..b57aef10798d 100644 --- a/layout/xul/nsMenuBarFrame.cpp +++ b/layout/xul/nsMenuBarFrame.cpp @@ -82,9 +82,9 @@ nsMenuBarFrame::Init(nsIContent* aContent, mTarget->AddSystemEventListener(NS_LITERAL_STRING("keyup"), mMenuBarListener, false); // mousedown event should be handled in all phase - mTarget->AddSystemEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, true); - mTarget->AddSystemEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, false); - mTarget->AddSystemEventListener(NS_LITERAL_STRING("blur"), mMenuBarListener, true); + mTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, true); + mTarget->AddEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, false); + mTarget->AddEventListener(NS_LITERAL_STRING("blur"), mMenuBarListener, true); } NS_IMETHODIMP @@ -416,9 +416,9 @@ nsMenuBarFrame::DestroyFrom(nsIFrame* aDestructRoot) mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keydown"), mMenuBarListener, false); mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keyup"), mMenuBarListener, false); - mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, true); - mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, false); - mTarget->RemoveSystemEventListener(NS_LITERAL_STRING("blur"), mMenuBarListener, true); + mTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, true); + mTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, false); + mTarget->RemoveEventListener(NS_LITERAL_STRING("blur"), mMenuBarListener, true); NS_IF_RELEASE(mMenuBarListener); From 55a8118ad104eeb50e69c45ace2918998bbc6f80 Mon Sep 17 00:00:00 2001 From: Monica Chew Date: Thu, 18 Dec 2014 10:18:09 -0800 Subject: [PATCH 17/17] Bug 1108009 - Make synchronous interface nsIURIClassifier.ClassifyLocal. r=gcp --- netwerk/base/public/nsIURIClassifier.idl | 10 +- .../components/url-classifier/Classifier.cpp | 18 +- .../components/url-classifier/Classifier.h | 4 +- .../nsIUrlClassifierDBService.idl | 4 +- .../nsUrlClassifierDBService.cpp | 213 +++++++++++++----- .../url-classifier/nsUrlClassifierDBService.h | 5 + .../url-classifier/nsUrlClassifierProxies.cpp | 9 + 7 files changed, 200 insertions(+), 63 deletions(-) diff --git a/netwerk/base/public/nsIURIClassifier.idl b/netwerk/base/public/nsIURIClassifier.idl index a8b5920cfbe7..f6fd0214cc94 100644 --- a/netwerk/base/public/nsIURIClassifier.idl +++ b/netwerk/base/public/nsIURIClassifier.idl @@ -30,7 +30,7 @@ interface nsIURIClassifierCallback : nsISupports * The URI classifier service checks a URI against lists of phishing * and malware sites. */ -[scriptable, uuid(de4f03cd-1a28-4f51-906b-c54b47a533c5)] +[scriptable, uuid(03d26681-0ef5-4718-9777-33c9e1ee3e32)] interface nsIURIClassifier : nsISupports { /** @@ -54,4 +54,12 @@ interface nsIURIClassifier : nsISupports boolean classify(in nsIPrincipal aPrincipal, in boolean aTrackingProtectionEnabled, in nsIURIClassifierCallback aCallback); + + /** + * Synchronously classify a Principal locally using its URI. This does not + * make network requests. The result is an error code with which the channel + * should be cancelled, or NS_OK if no result was found. + */ + nsresult classifyLocal(in nsIPrincipal aPrincipal, + in boolean aTrackingProtectionEnabled); }; diff --git a/toolkit/components/url-classifier/Classifier.cpp b/toolkit/components/url-classifier/Classifier.cpp index 1ee34737189c..aeb1208c8eff 100644 --- a/toolkit/components/url-classifier/Classifier.cpp +++ b/toolkit/components/url-classifier/Classifier.cpp @@ -11,6 +11,7 @@ #include "nsIInputStream.h" #include "nsISeekableStream.h" #include "nsIFile.h" +#include "nsThreadUtils.h" #include "mozilla/Telemetry.h" #include "prlog.h" @@ -54,7 +55,6 @@ Classifier::SplitTables(const nsACString& str, nsTArray& tables) } Classifier::Classifier() - : mFreshTime(45 * 60) { } @@ -144,6 +144,9 @@ Classifier::Open(nsIFile& aCacheDirectory) rv = CreateStoreDirectory(); NS_ENSURE_SUCCESS(rv, rv); + // Classifier keeps its own cryptoHash for doing operations on the background + // thread. Callers can optionally pass in an nsICryptoHash for working on the + // main thread. mCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); @@ -216,8 +219,15 @@ Classifier::TableRequest(nsACString& aResult) nsresult Classifier::Check(const nsACString& aSpec, const nsACString& aTables, + uint32_t aFreshnessGuarantee, + nsICryptoHash* aCryptoHash, LookupResultArray& aResults) { + nsCOMPtr cryptoHash = aCryptoHash; + if (!aCryptoHash) { + MOZ_ASSERT(!NS_IsMainThread(), "mCryptoHash must be used on worker thread"); + cryptoHash = mCryptoHash; + } Telemetry::AutoTimer timer; // Get the set of fragments based on the url. This is necessary because we @@ -244,11 +254,11 @@ Classifier::Check(const nsACString& aSpec, // Now check each lookup fragment against the entries in the DB. for (uint32_t i = 0; i < fragments.Length(); i++) { Completion lookupHash; - lookupHash.FromPlaintext(fragments[i], mCryptoHash); + lookupHash.FromPlaintext(fragments[i], cryptoHash); // Get list of host keys to look up Completion hostKey; - rv = LookupCache::GetKey(fragments[i], &hostKey, mCryptoHash); + rv = LookupCache::GetKey(fragments[i], &hostKey, cryptoHash); if (NS_FAILED(rv)) { // Local host on the network. continue; @@ -288,7 +298,7 @@ Classifier::Check(const nsACString& aSpec, result->hash.complete = lookupHash; result->mComplete = complete; - result->mFresh = (age < mFreshTime); + result->mFresh = (age < aFreshnessGuarantee); result->mTableName.Assign(cache->TableName()); } } diff --git a/toolkit/components/url-classifier/Classifier.h b/toolkit/components/url-classifier/Classifier.h index 246b3cd714c9..eff8afb4dc74 100644 --- a/toolkit/components/url-classifier/Classifier.h +++ b/toolkit/components/url-classifier/Classifier.h @@ -47,6 +47,8 @@ public: */ nsresult Check(const nsACString& aSpec, const nsACString& tables, + uint32_t aFreshnessGuarantee, + nsICryptoHash* aCryptoHash, LookupResultArray& aResults); /** @@ -61,7 +63,6 @@ public: nsresult MarkSpoiled(nsTArray& aTables); nsresult CacheCompletions(const CacheResultArray& aResults); uint32_t GetHashKey(void) { return mHashKey; } - void SetFreshTime(uint32_t aTime) { mFreshTime = aTime; } /* * Get a bunch of extra prefixes to query for completion * and mask the real entry being requested @@ -102,7 +103,6 @@ private: uint32_t mHashKey; // Stores the last time a given table was updated (seconds). nsDataHashtable mTableFreshness; - uint32_t mFreshTime; }; } diff --git a/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl b/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl index 5fae66527683..efe508e7bd6e 100644 --- a/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl +++ b/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl @@ -185,9 +185,11 @@ interface nsIUrlClassifierDBService : nsISupports * Interface for the actual worker thread. Implementations of this need not * be thread aware and just work on the database. */ -[scriptable, uuid(abcd7978-c304-4a7d-a44c-33c2ed5441e7)] +[scriptable, uuid(b7b505d0-bfa2-44db-abf8-6e2bfc25bbab)] interface nsIUrlClassifierDBServiceWorker : nsIUrlClassifierDBService { + // Open the DB connection + void openDb(); // Provide a way to forcibly close the db connection. void closeDb(); diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp index 00ae4d32fd96..138565223ab6 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp @@ -121,6 +121,13 @@ public: // update operations to prevent lookups from blocking for too long. nsresult HandlePendingLookups(); + // Perform a blocking classifier lookup for a given url. Can be called on + // either the main thread or the worker thread. + nsresult DoLocalLookup(const nsACString& spec, + const nsACString& tables, + nsICryptoHash* cryptoHash, + LookupResultArray* results); + private: // No subclassing ~nsUrlClassifierDBServiceWorker(); @@ -128,8 +135,6 @@ private: // Disallow copy constructor nsUrlClassifierDBServiceWorker(nsUrlClassifierDBServiceWorker&); - nsresult OpenDb(); - // Applies the current transaction and resets the update/working times. nsresult ApplyUpdate(); @@ -149,6 +154,7 @@ private: uint32_t aCount, LookupResultArray& results); + // Can only be used on the background thread nsCOMPtr mCryptoHash; nsAutoPtr mClassifier; @@ -241,6 +247,76 @@ nsUrlClassifierDBServiceWorker::QueueLookup(const nsACString& spec, return NS_OK; } +nsresult +nsUrlClassifierDBServiceWorker::DoLocalLookup(const nsACString& spec, + const nsACString& tables, + nsICryptoHash* cryptoHash, + LookupResultArray* results) +{ + LOG(("nsUrlClassifierDBServiceWorker::DoLocalLookup %s (main=%s) %p", + spec.Data(), NS_IsMainThread() ? "true" : "false", this)); + if (!results) { + return NS_ERROR_FAILURE; + } + // Bail if we haven't been initialized on the background thread. + if (!mClassifier) { + return NS_ERROR_NOT_AVAILABLE; + } + + // We ignore failures from Check because we'd rather return the + // results that were found than fail. + mClassifier->Check(spec, tables, gFreshnessGuarantee, cryptoHash, *results); + + LOG(("Found %d results.", results->Length())); + return NS_OK; +} + +static nsresult +TablesToResponse(const nsACString& tables, + bool checkMalware, + bool checkPhishing, + bool checkTracking) +{ + if (checkMalware && + FindInReadable(NS_LITERAL_CSTRING("-malware-"), tables)) { + return NS_ERROR_MALWARE_URI; + } + if (checkPhishing && + FindInReadable(NS_LITERAL_CSTRING("-phish-"), tables)) { + return NS_ERROR_PHISHING_URI; + } + if (checkTracking && + FindInReadable(NS_LITERAL_CSTRING("-track-"), tables)) { + return NS_ERROR_TRACKING_URI; + } + return NS_OK; +} + +static nsresult +ProcessLookupResults(LookupResultArray* results, + bool checkMalware, + bool checkPhishing, + bool checkTracking) +{ + // Build a stringified list of result tables. + nsTArray tables; + for (uint32_t i = 0; i < results->Length(); i++) { + LookupResult& result = results->ElementAt(i); + MOZ_ASSERT(!result.mNoise, "Lookup results should not have noise added"); + LOG(("Found result from table %s", result.mTableName.get())); + if (tables.IndexOf(result.mTableName) == nsTArray::NoIndex) { + tables.AppendElement(result.mTableName); + } + } + nsAutoCString tableStr; + for (uint32_t i = 0; i < tables.Length(); i++) { + if (i != 0) + tableStr.Append(','); + tableStr.Append(tables[i]); + } + return TablesToResponse(tableStr, checkMalware, checkPhishing, checkTracking); +} + /** * Lookup up a key in the database is a two step process: * @@ -262,13 +338,6 @@ nsUrlClassifierDBServiceWorker::DoLookup(const nsACString& spec, return NS_ERROR_NOT_INITIALIZED; } - nsresult rv = OpenDb(); - if (NS_FAILED(rv)) { - c->LookupComplete(nullptr); - NS_ERROR("Unable to open SafeBrowsing database."); - return NS_ERROR_FAILURE; - } - #if defined(PR_LOGGING) PRIntervalTime clockStart = 0; if (LOG_ENABLED()) { @@ -282,10 +351,11 @@ nsUrlClassifierDBServiceWorker::DoLookup(const nsACString& spec, return NS_ERROR_OUT_OF_MEMORY; } - // we ignore failures from Check because we'd rather return the - // results that were found than fail. - mClassifier->SetFreshTime(gFreshnessGuarantee); - mClassifier->Check(spec, tables, *results); + nsresult rv = DoLocalLookup(spec, tables, nullptr, results); + if (NS_FAILED(rv)) { + c->LookupComplete(nullptr); + return rv; + } LOG(("Found %d results.", results->Length())); @@ -457,6 +527,7 @@ NS_IMETHODIMP nsUrlClassifierDBServiceWorker::BeginStream(const nsACString &table) { LOG(("nsUrlClassifierDBServiceWorker::BeginStream")); + MOZ_ASSERT(!NS_IsMainThread(), "Streaming must be on the background thread"); if (gShuttingDownThread) return NS_ERROR_NOT_INITIALIZED; @@ -732,13 +803,12 @@ nsUrlClassifierDBServiceWorker::CacheMisses(PrefixArray *results) nsresult nsUrlClassifierDBServiceWorker::OpenDb() { + MOZ_ASSERT(!NS_IsMainThread(), "Must initialize DB on background thread"); // Connection already open, don't do anything. if (mClassifier) { return NS_OK; } - LOG(("Opening db")); - nsresult rv; mCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); @@ -748,8 +818,6 @@ nsUrlClassifierDBServiceWorker::OpenDb() return NS_ERROR_OUT_OF_MEMORY; } - classifier->SetFreshTime(gFreshnessGuarantee); - rv = classifier->Open(*mCacheDir); NS_ENSURE_SUCCESS(rv, rv); @@ -1025,25 +1093,9 @@ NS_IMPL_ISUPPORTS(nsUrlClassifierClassifyCallback, NS_IMETHODIMP nsUrlClassifierClassifyCallback::HandleEvent(const nsACString& tables) { - // XXX: we should probably have the wardens tell the service which table - // names match with which classification. For now the table names give - // enough information. - nsresult response = NS_OK; - - if (mCheckMalware && - FindInReadable(NS_LITERAL_CSTRING("-malware-"), tables)) { - response = NS_ERROR_MALWARE_URI; - } else if (mCheckPhishing && - FindInReadable(NS_LITERAL_CSTRING("-phish-"), tables)) { - response = NS_ERROR_PHISHING_URI; - } else if (mCheckTracking && - FindInReadable(NS_LITERAL_CSTRING("-track-"), tables)) { - LOG(("Blocking tracking uri [this=%p]", this)); - response = NS_ERROR_TRACKING_URI; - } - + nsresult response = TablesToResponse(tables, mCheckMalware, + mCheckPhishing, mCheckTracking); mCallback->OnClassifyComplete(response); - return NS_OK; } @@ -1141,6 +1193,7 @@ nsUrlClassifierDBService::Init() if (!gUrlClassifierDbServiceLog) gUrlClassifierDbServiceLog = PR_NewLogModule("UrlClassifierDbService"); #endif + MOZ_ASSERT(NS_IsMainThread(), "Must initialize DB service on main thread"); // Retrieve all the preferences. mCheckMalware = Preferences::GetBool(CHECK_MALWARE_PREF, @@ -1170,7 +1223,7 @@ nsUrlClassifierDBService::Init() // Force PSM loading on main thread nsresult rv; - nsCOMPtr acryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); + mCryptoHashMain = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); // Directory providers must also be accessed on the main thread. @@ -1199,6 +1252,10 @@ nsUrlClassifierDBService::Init() // Proxy for calling the worker on the background thread mWorkerProxy = new UrlClassifierDBServiceWorkerProxy(mWorker); + rv = mWorkerProxy->OpenDb(); + if (NS_FAILED(rv)) { + return rv; + } // Add an observer for shutdown nsCOMPtr observerService = @@ -1212,6 +1269,28 @@ nsUrlClassifierDBService::Init() return NS_OK; } +static void BuildTables(bool aTrackingProtectionEnabled, nsCString &tables) +{ + nsAutoCString malware; + // LookupURI takes a comma-separated list already. + Preferences::GetCString(MALWARE_TABLE_PREF, &malware); + if (!malware.IsEmpty()) { + tables.Append(malware); + } + nsAutoCString phishing; + Preferences::GetCString(PHISH_TABLE_PREF, &phishing); + if (!phishing.IsEmpty()) { + tables.Append(','); + tables.Append(phishing); + } + nsAutoCString tracking; + Preferences::GetCString(TRACKING_TABLE_PREF, &tracking); + if (aTrackingProtectionEnabled && !tracking.IsEmpty()) { + tables.Append(','); + tables.Append(tracking); + } +} + // nsChannelClassifier is the only consumer of this interface. NS_IMETHODIMP nsUrlClassifierDBService::Classify(nsIPrincipal* aPrincipal, @@ -1233,25 +1312,8 @@ nsUrlClassifierDBService::Classify(nsIPrincipal* aPrincipal, if (!callback) return NS_ERROR_OUT_OF_MEMORY; nsAutoCString tables; - nsAutoCString malware; - // LookupURI takes a comma-separated list already. - Preferences::GetCString(MALWARE_TABLE_PREF, &malware); - if (!malware.IsEmpty()) { - tables.Append(malware); - } - nsAutoCString phishing; - Preferences::GetCString(PHISH_TABLE_PREF, &phishing); - if (!phishing.IsEmpty()) { - tables.Append(','); - tables.Append(phishing); - } - nsAutoCString tracking; - Preferences::GetCString(TRACKING_TABLE_PREF, &tracking); - if (aTrackingProtectionEnabled && !tracking.IsEmpty()) { - LOG(("Looking up third party in tracking table, [cb=%p]", callback.get())); - tables.Append(','); - tables.Append(tracking); - } + BuildTables(aTrackingProtectionEnabled, tables); + nsresult rv = LookupURI(aPrincipal, tables, callback, false, result); if (rv == NS_ERROR_MALFORMED_URI) { *result = false; @@ -1263,6 +1325,47 @@ nsUrlClassifierDBService::Classify(nsIPrincipal* aPrincipal, return NS_OK; } +NS_IMETHODIMP +nsUrlClassifierDBService::ClassifyLocal(nsIPrincipal* aPrincipal, + bool aTrackingProtectionEnabled, + nsresult* aResponse) +{ + MOZ_ASSERT(NS_IsMainThread(), "ClassifyLocal must be on main thread"); + *aResponse = NS_OK; + nsAutoCString tables; + BuildTables(aTrackingProtectionEnabled, tables); + + nsCOMPtr uri; + nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); + + uri = NS_GetInnermostURI(uri); + NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); + + nsAutoCString key; + // Canonicalize the url + nsCOMPtr utilsService = + do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID); + rv = utilsService->GetKeyForURI(uri, key); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoPtr results(new LookupResultArray()); + if (!results) { + return NS_ERROR_OUT_OF_MEMORY; + } + + // We don't use the proxy, since this is a blocking lookup. In unittests, we + // may not have been initalized, so don't crash. + rv = mWorker->DoLocalLookup(key, tables, mCryptoHashMain, results); + if (NS_SUCCEEDED(rv)) { + rv = ProcessLookupResults(results, mCheckMalware, mCheckPhishing, + mCheckTracking); + *aResponse = rv; + } + return NS_OK; +} + NS_IMETHODIMP nsUrlClassifierDBService::Lookup(nsIPrincipal* aPrincipal, const nsACString& tables, diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.h b/toolkit/components/url-classifier/nsUrlClassifierDBService.h index 06be18acb74e..9089da63baf9 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.h +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.h @@ -33,6 +33,7 @@ #define COMPLETE_LENGTH 32 class nsUrlClassifierDBServiceWorker; +class nsICryptoHash; class nsIThread; class nsIURI; @@ -117,6 +118,10 @@ private: // Thread that we do the updates on. static nsIThread* gDbBackgroundThread; + + // nsICryptoHash for doing hash operations on the main thread. This is only + // used for nsIURIClassifier.ClassifyLocal + nsCOMPtr mCryptoHashMain; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsUrlClassifierDBService, NS_URLCLASSIFIERDBSERVICE_CID) diff --git a/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp b/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp index 150d0b2fd5d4..fba5ada85be8 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp @@ -143,6 +143,15 @@ UrlClassifierDBServiceWorkerProxy::ResetDatabase() return DispatchToWorkerThread(r); } +NS_IMETHODIMP +UrlClassifierDBServiceWorkerProxy::OpenDb() +{ + nsCOMPtr r = + NS_NewRunnableMethod(mTarget, + &nsIUrlClassifierDBServiceWorker::OpenDb); + return DispatchToWorkerThread(r); +} + NS_IMETHODIMP UrlClassifierDBServiceWorkerProxy::CloseDb() {