Merge inbound to mozilla-central a=merge CLOSED TREE

This commit is contained in:
Wes Kocher 2014-12-23 16:47:42 -08:00
commit ab27d8e9b0
75 changed files with 2940 additions and 285 deletions

View File

@ -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)

View File

@ -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<nsFontMetrics> 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

View File

@ -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<mozilla::RefPtr<mozilla::gfx::SourceSurface>> filterAdditionalImages;
bool imageSmoothingEnabled;
bool fontExplicitLanguage;
};
nsAutoTArray<ContextState, 3> mStyleStack;

View File

@ -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);

View File

@ -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

View File

@ -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) {

View File

@ -2624,12 +2624,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);
@ -2685,7 +2685,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);
@ -2706,7 +2706,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());

View File

@ -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;

View File

@ -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

View File

@ -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)));

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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,

View File

@ -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(),

View File

@ -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,

View File

@ -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));

View File

@ -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);
@ -3584,13 +3586,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 +3610,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 +3649,7 @@ gfxFontStyle::gfxFontStyle(const gfxFontStyle& aStyle) :
allowSyntheticWeight(aStyle.allowSyntheticWeight),
allowSyntheticStyle(aStyle.allowSyntheticStyle),
noFallbackVariantFeatures(aStyle.noFallbackVariantFeatures),
explicitLanguage(aStyle.explicitLanguage),
variantCaps(aStyle.variantCaps),
variantSubSuper(aStyle.variantSubSuper)
{

View File

@ -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) &&

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -0,0 +1,2 @@
(new Function("return (function o() {}).caller;"))();

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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<nsFontMetrics> 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);

View File

@ -739,8 +739,10 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
font.size = NSToCoordRound(font.size * mFontInflation);
nsPresContext* pc = styles[0]->PresContext();
nsRefPtr<nsFontMetrics> 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(),

View File

@ -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<nsPoint*>
(Properties().Get(NormalPositionProperty()));
if (normalPosition) {
return nsRect(*normalPosition, GetSize());
}
return GetRect();
}
nsPoint
nsIFrame::GetNormalPosition() const
{

View File

@ -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
*/

View File

@ -598,7 +598,7 @@ nsPageFrame::PaintHeaderFooter(nsRenderingContext& aRenderingContext,
// Get the FontMetrics to determine width.height of strings
nsRefPtr<nsFontMetrics> fontMet;
pc->DeviceContext()->GetMetricsFor(mPD->mHeadFootFont, nullptr,
pc->DeviceContext()->GetMetricsFor(mPD->mHeadFootFont, nullptr, false,
gfxFont::eHorizontal,
pc->GetUserFontSet(),
pc->GetTextPerfMetrics(),

View File

@ -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();

View File

@ -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<nsFontMetrics> 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<nsFontMetrics> fm;
aPresContext->DeviceContext()->
GetMetricsFor(font,
mStyleContext->StyleFont()->mLanguage,
styleFont->mLanguage,
styleFont->mExplicitLanguage,
gfxFont::eHorizontal,
aPresContext->GetUserFontSet(),
aPresContext->GetTextPerfMetrics(),

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Bug 983985</title>
<style>
@font-face {
font-family: test;
src: url(../fonts/dejavu-sans/DejaVuSans.ttf);
}
body {
font: 36px test;
}
</style>
</head>
<body>
hello &#x530; world
</body>
</html>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Bug 983985</title>
<style>
@font-face {
font-family: test;
src: url(../fonts/dejavu-sans/DejaVuSans.ttf);
}
body {
font: 36px test;
}
</style>
</head>
<body>
hello <i>&#x530;</i> world
</body>
</html>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Bug 983985</title>
<style>
@font-face {
font-family: test;
src: url(../fonts/dejavu-sans/DejaVuSans.ttf);
}
.outer {
font: italic 36px test;
width: 2.5em; /* enough to display "hello" but not the hexbox */
overflow: hidden;
}
.inner {
width: 10em;
}
</style>
</head>
<body>
<div class="outer">
<div class="inner">
hello <em>&#x530;</em> world
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Bug 983985</title>
<style>
@font-face {
font-family: test;
src: url(../fonts/dejavu-sans/DejaVuSans.ttf);
}
.outer {
font: italic 36px test;
width: 2.5em; /* enough to display "hello" but not the hexbox */
overflow: hidden;
}
.inner {
width: 10em;
}
</style>
</head>
<body>
<div class="outer">
<div class="inner">
hello &#x530; world
</div>
</div>
</body>
</html>

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,180 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
border-collapse: collapse;
position: absolute;
}
#first-table {
left: 0px;
}
#second-table {
left: 100px;
}
#third-table {
left: 200px;
}
#fourth-table {
left: 300px;
}
td {
border-style: solid;
border-width: 5px;
border-color: transparent;
color: rgba(0,0,0,0);
}
#first-table td {
border-color: gold;
}
.bg-blue {
background-color: blue;
}
.bg-cyan {
background-color: cyan;
}
.bg-grey {
background-color: grey;
}
.bg-green {
background-color: green;
}
.bg-khaki {
background-color: khaki;
}
.bg-purple {
background-color: purple;
}
.bg-white {
background-color: white;
}
.show-text {
color: rgba(0,0,0,1);
}
</style>
</head>
<body>
<table id="first-table">
<thead>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
<td rowspan=2 class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-khaki">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
</tfoot>
</table>
<table id="second-table">
<thead>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-green">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td rowspan=2 class="bg-green">YYY</td>
</tr>
<tr>
<td class="bg-grey show-text">&nbsp;</td>
</tr>
<tr>
<td colspan=2 class="bg-green">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white show-text">&nbsp;</td>
</tr>
</tfoot>
</table>
<table id="third-table">
<thead>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td rowspan=2 class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-green">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-cyan show-text">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
<table id="fourth-table">
<thead>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white" rowspan=2>YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
</tr>
<tr>
<td class="bg-white" colspan=2>XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,80 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
background-color: red;
border-collapse: collapse;
}
thead {
background-color: pink;
}
tbody {
background-color: grey;
}
tfoot {
background-color: orange;
}
tr {
background-color: green;
}
td:first-child {
background-color: cyan;
}
td {
background-color: blue;
border-style: solid;
border-width: 5px;
border-color: gold;
}
colgroup {
background-color: purple;
}
col:first-child {
background-color: khaki;
}
.rel {
position: relative;
left: 100px;
}
</style>
</head>
<body>
<table>
<colgroup>
<col>
<col>
</colgroup>
<thead class="rel">
<tr>
<td class="rel">XXX</td>
<td class="rel">YYY</td>
</tr>
</thead>
<tbody class="rel">
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
<tr>
<td>XXX</td>
<td rowspan=2 class="rel">YYY</td>
</tr>
<tr class="rel">
<td class="rel">XXX</td>
</tr>
<tr>
<td colspan=2 class="rel">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,180 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
border-collapse: collapse;
position: absolute;
}
#first-table {
left: 300px;
}
#second-table {
left: 200px;
}
#third-table {
left: 100px;
}
#fourth-table {
left: 0px;
}
td {
border-style: solid;
border-width: 5px;
border-color: transparent;
color: rgba(0,0,0,0);
}
#first-table td {
border-color: gold;
}
.bg-blue {
background-color: blue;
}
.bg-cyan {
background-color: cyan;
}
.bg-grey {
background-color: grey;
}
.bg-green {
background-color: green;
}
.bg-khaki {
background-color: khaki;
}
.bg-purple {
background-color: purple;
}
.bg-white {
background-color: white;
}
.show-text {
color: rgba(0,0,0,1);
}
</style>
</head>
<body>
<table id="first-table">
<thead>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
<td rowspan=2 class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-khaki">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
</tfoot>
</table>
<table id="second-table">
<thead>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-green">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td rowspan=2 class="bg-green">YYY</td>
</tr>
<tr>
<td class="bg-grey show-text">&nbsp;</td>
</tr>
<tr>
<td colspan=2 class="bg-green">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white show-text">&nbsp;</td>
</tr>
</tfoot>
</table>
<table id="third-table">
<thead>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td rowspan=2 class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-green">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-cyan show-text">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
<table id="fourth-table">
<thead>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white" rowspan=2>YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
</tr>
<tr>
<td class="bg-white" colspan=2>XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
background-color: red;
border-collapse: collapse;
position: absolute;
left: 300px;
}
thead {
background-color: pink;
}
tbody {
background-color: grey;
}
tfoot {
background-color: orange;
}
tr {
background-color: green;
}
td:first-child {
background-color: cyan;
}
td {
background-color: blue;
border-style: solid;
border-width: 5px;
border-color: gold;
}
colgroup {
background-color: purple;
}
col:first-child {
background-color: khaki;
}
.rel {
position: relative;
right: 100px;
}
</style>
</head>
<body>
<table>
<colgroup>
<col>
<col>
</colgroup>
<thead class="rel">
<tr>
<td class="rel">XXX</td>
<td class="rel">YYY</td>
</tr>
</thead>
<tbody class="rel">
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
<tr>
<td>XXX</td>
<td rowspan=2 class="rel">YYY</td>
</tr>
<tr class="rel">
<td class="rel">XXX</td>
</tr>
<tr>
<td colspan=2 class="rel">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,180 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
border-collapse: collapse;
position: absolute;
}
#first-table {
top: 0px;
}
#second-table {
top: 175px;
}
#third-table {
top: 350px;
}
#fourth-table {
top: 525px;
}
td {
border-style: solid;
border-width: 5px;
border-color: transparent;
color: rgba(0,0,0,0);
}
#first-table td {
border-color: gold;
}
.bg-blue {
background-color: blue;
}
.bg-cyan {
background-color: cyan;
}
.bg-grey {
background-color: grey;
}
.bg-green {
background-color: green;
}
.bg-khaki {
background-color: khaki;
}
.bg-purple {
background-color: purple;
}
.bg-white {
background-color: white;
}
.show-text {
color: rgba(0,0,0,1);
}
</style>
</head>
<body>
<table id="first-table">
<thead>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
<td rowspan=2 class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-khaki">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
</tfoot>
</table>
<table id="second-table">
<thead>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-green">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td rowspan=2 class="bg-green">YYY</td>
</tr>
<tr>
<td class="bg-grey show-text">&nbsp;</td>
</tr>
<tr>
<td colspan=2 class="bg-green">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white show-text">&nbsp;</td>
</tr>
</tfoot>
</table>
<table id="third-table">
<thead>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td rowspan=2 class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-green">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-cyan show-text">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
<table id="fourth-table">
<thead>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white" rowspan=2>YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
</tr>
<tr>
<td class="bg-white" colspan=2>XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,80 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
background-color: red;
border-collapse: collapse;
}
thead {
background-color: pink;
}
tbody {
background-color: grey;
}
tfoot {
background-color: orange;
}
tr {
background-color: green;
}
td:first-child {
background-color: cyan;
}
td {
background-color: blue;
border-style: solid;
border-width: 5px;
border-color: gold;
}
colgroup {
background-color: purple;
}
col:first-child {
background-color: khaki;
}
.rel {
position: relative;
top: 175px;
}
</style>
</head>
<body>
<table>
<colgroup>
<col>
<col>
</colgroup>
<thead class="rel">
<tr>
<td class="rel">XXX</td>
<td class="rel">YYY</td>
</tr>
</thead>
<tbody class="rel">
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
<tr>
<td>XXX</td>
<td rowspan=2 class="rel">YYY</td>
</tr>
<tr class="rel">
<td class="rel">XXX</td>
</tr>
<tr>
<td colspan=2 class="rel">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,180 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
border-collapse: collapse;
position: absolute;
}
#first-table {
top: 525px;
}
#second-table {
top: 350px;
}
#third-table {
top: 175px;
}
#fourth-table {
top: 0px;
}
td {
border-style: solid;
border-width: 5px;
border-color: transparent;
color: rgba(0,0,0,0);
}
#first-table td {
border-color: gold;
}
.bg-blue {
background-color: blue;
}
.bg-cyan {
background-color: cyan;
}
.bg-grey {
background-color: grey;
}
.bg-green {
background-color: green;
}
.bg-khaki {
background-color: khaki;
}
.bg-purple {
background-color: purple;
}
.bg-white {
background-color: white;
}
.show-text {
color: rgba(0,0,0,1);
}
</style>
</head>
<body>
<table id="first-table">
<thead>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
<td rowspan=2 class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-khaki">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
</tfoot>
</table>
<table id="second-table">
<thead>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-green">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td rowspan=2 class="bg-green">YYY</td>
</tr>
<tr>
<td class="bg-grey show-text">&nbsp;</td>
</tr>
<tr>
<td colspan=2 class="bg-green">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white show-text">&nbsp;</td>
</tr>
</tfoot>
</table>
<table id="third-table">
<thead>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td rowspan=2 class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-green">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-cyan show-text">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
<table id="fourth-table">
<thead>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white" rowspan=2>YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
</tr>
<tr>
<td class="bg-white" colspan=2>XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
background-color: red;
border-collapse: collapse;
position: absolute;
top: 525px;
}
thead {
background-color: pink;
}
tbody {
background-color: grey;
}
tfoot {
background-color: orange;
}
tr {
background-color: green;
}
td:first-child {
background-color: cyan;
}
td {
background-color: blue;
border-style: solid;
border-width: 5px;
border-color: gold;
}
colgroup {
background-color: purple;
}
col:first-child {
background-color: khaki;
}
.rel {
position: relative;
bottom: 175px;
}
</style>
</head>
<body>
<table>
<colgroup>
<col>
<col>
</colgroup>
<thead class="rel">
<tr>
<td class="rel">XXX</td>
<td class="rel">YYY</td>
</tr>
</thead>
<tbody class="rel">
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
<tr>
<td>XXX</td>
<td rowspan=2 class="rel">YYY</td>
</tr>
<tr class="rel">
<td class="rel">XXX</td>
</tr>
<tr>
<td colspan=2 class="rel">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,179 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
border-collapse: separate;
position: absolute;
}
#first-table {
background-color: red;
left: 0px;
}
#second-table {
left: 100px;
}
#third-table {
left: 200px;
}
#fourth-table {
left: 300px;
}
td {
border-style: solid;
border-width: 5px;
border-color: transparent;
color: rgba(0,0,0,0);
}
.bg-blue {
background-color: blue;
}
.bg-cyan {
background-color: cyan;
}
.bg-grey {
background-color: grey;
}
.bg-green {
background-color: green;
}
.bg-khaki {
background-color: khaki;
}
.bg-purple {
background-color: purple;
}
.bg-white {
background-color: white;
}
.show-text {
border-color: gold;
color: rgba(0,0,0,1);
}
</style>
</head>
<body>
<table id="first-table">
<thead>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
<td rowspan=2 class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-khaki">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-border show-text">YYY</td>
</tr>
</tfoot>
</table>
<table id="second-table">
<thead>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-green">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td rowspan=2 class="bg-green">YYY</td>
</tr>
<tr>
<td class="bg-grey">&nbsp;</td>
</tr>
<tr>
<td colspan=2 class="bg-green">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white">&nbsp;</td>
</tr>
</tfoot>
</table>
<table id="third-table">
<thead>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td rowspan=2 class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-green">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-cyan show-text">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
<table id="fourth-table">
<thead>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white" rowspan=2>YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
</tr>
<tr>
<td class="bg-white" colspan=2>XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,80 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
background-color: red;
border-collapse: separate;
}
thead {
background-color: pink;
}
tbody {
background-color: grey;
}
tfoot {
background-color: orange;
}
tr {
background-color: green;
}
td:first-child {
background-color: cyan;
}
td {
background-color: blue;
border-style: solid;
border-width: 5px;
border-color: gold;
}
colgroup {
background-color: purple;
}
col:first-child {
background-color: khaki;
}
.rel {
position: relative;
left: 100px;
}
</style>
</head>
<body>
<table>
<colgroup>
<col>
<col>
</colgroup>
<thead class="rel">
<tr>
<td class="rel">XXX</td>
<td class="rel">YYY</td>
</tr>
</thead>
<tbody class="rel">
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
<tr>
<td>XXX</td>
<td rowspan=2 class="rel">YYY</td>
</tr>
<tr class="rel">
<td class="rel">XXX</td>
</tr>
<tr>
<td colspan=2 class="rel">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,179 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
border-collapse: separate;
position: absolute;
}
#first-table {
background-color: red;
left: 300px;
}
#second-table {
left: 200px;
}
#third-table {
left: 100px;
}
#fourth-table {
left: 0px;
}
td {
border-style: solid;
border-width: 5px;
border-color: transparent;
color: rgba(0,0,0,0);
}
.bg-blue {
background-color: blue;
}
.bg-cyan {
background-color: cyan;
}
.bg-grey {
background-color: grey;
}
.bg-green {
background-color: green;
}
.bg-khaki {
background-color: khaki;
}
.bg-purple {
background-color: purple;
}
.bg-white {
background-color: white;
}
.show-text {
border-color: gold;
color: rgba(0,0,0,1);
}
</style>
</head>
<body>
<table id="first-table">
<thead>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
<td rowspan=2 class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-khaki">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-border show-text">YYY</td>
</tr>
</tfoot>
</table>
<table id="second-table">
<thead>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-green">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td rowspan=2 class="bg-green">YYY</td>
</tr>
<tr>
<td class="bg-grey">&nbsp;</td>
</tr>
<tr>
<td colspan=2 class="bg-green">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white">&nbsp;</td>
</tr>
</tfoot>
</table>
<table id="third-table">
<thead>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td rowspan=2 class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-green">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-cyan show-text">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
<table id="fourth-table">
<thead>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white" rowspan=2>YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
</tr>
<tr>
<td class="bg-white" colspan=2>XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
background-color: red;
border-collapse: separate;
position: absolute;
left: 300px;
}
thead {
background-color: pink;
}
tbody {
background-color: grey;
}
tfoot {
background-color: orange;
}
tr {
background-color: green;
}
td:first-child {
background-color: cyan;
}
td {
background-color: blue;
border-style: solid;
border-width: 5px;
border-color: gold;
}
colgroup {
background-color: purple;
}
col:first-child {
background-color: khaki;
}
.rel {
position: relative;
right: 100px;
}
</style>
</head>
<body>
<table>
<colgroup>
<col>
<col>
</colgroup>
<thead class="rel">
<tr>
<td class="rel">XXX</td>
<td class="rel">YYY</td>
</tr>
</thead>
<tbody class="rel">
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
<tr>
<td>XXX</td>
<td rowspan=2 class="rel">YYY</td>
</tr>
<tr class="rel">
<td class="rel">XXX</td>
</tr>
<tr>
<td colspan=2 class="rel">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,179 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
border-collapse: separate;
position: absolute;
}
#first-table {
background-color: red;
top: 0px;
}
#second-table {
top: 215px;
}
#third-table {
top: 430px;
}
#fourth-table {
top: 645px;
}
td {
border-style: solid;
border-width: 5px;
border-color: transparent;
color: rgba(0,0,0,0);
}
.bg-blue {
background-color: blue;
}
.bg-cyan {
background-color: cyan;
}
.bg-grey {
background-color: grey;
}
.bg-green {
background-color: green;
}
.bg-khaki {
background-color: khaki;
}
.bg-purple {
background-color: purple;
}
.bg-white {
background-color: white;
}
.show-text {
border-color: gold;
color: rgba(0,0,0,1);
}
</style>
</head>
<body>
<table id="first-table">
<thead>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
<td rowspan=2 class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-khaki">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-border show-text">YYY</td>
</tr>
</tfoot>
</table>
<table id="second-table">
<thead>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-green">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td rowspan=2 class="bg-green">YYY</td>
</tr>
<tr>
<td class="bg-grey">&nbsp;</td>
</tr>
<tr>
<td colspan=2 class="bg-green">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white">&nbsp;</td>
</tr>
</tfoot>
</table>
<table id="third-table">
<thead>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td rowspan=2 class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-green">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-cyan show-text">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
<table id="fourth-table">
<thead>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white" rowspan=2>YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
</tr>
<tr>
<td class="bg-white" colspan=2>XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,80 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
background-color: red;
border-collapse: separate;
}
thead {
background-color: pink;
}
tbody {
background-color: grey;
}
tfoot {
background-color: orange;
}
tr {
background-color: green;
}
td:first-child {
background-color: cyan;
}
td {
background-color: blue;
border-style: solid;
border-width: 5px;
border-color: gold;
}
colgroup {
background-color: purple;
}
col:first-child {
background-color: khaki;
}
.rel {
position: relative;
top: 215px;
}
</style>
</head>
<body>
<table>
<colgroup>
<col>
<col>
</colgroup>
<thead class="rel">
<tr>
<td class="rel">XXX</td>
<td class="rel">YYY</td>
</tr>
</thead>
<tbody class="rel">
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
<tr>
<td>XXX</td>
<td rowspan=2 class="rel">YYY</td>
</tr>
<tr class="rel">
<td class="rel">XXX</td>
</tr>
<tr>
<td colspan=2 class="rel">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,179 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
border-collapse: separate;
position: absolute;
}
#first-table {
background-color: red;
top: 645px;
}
#second-table {
top: 430px;
}
#third-table {
top: 215px;
}
#fourth-table {
top: 0px;
}
td {
border-style: solid;
border-width: 5px;
border-color: transparent;
color: rgba(0,0,0,0);
}
.bg-blue {
background-color: blue;
}
.bg-cyan {
background-color: cyan;
}
.bg-grey {
background-color: grey;
}
.bg-green {
background-color: green;
}
.bg-khaki {
background-color: khaki;
}
.bg-purple {
background-color: purple;
}
.bg-white {
background-color: white;
}
.show-text {
border-color: gold;
color: rgba(0,0,0,1);
}
</style>
</head>
<body>
<table id="first-table">
<thead>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-khaki">XXX</td>
<td class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
<td rowspan=2 class="bg-purple">YYY</td>
</tr>
<tr>
<td class="bg-khaki">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-khaki">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-border show-text">YYY</td>
</tr>
</tfoot>
</table>
<table id="second-table">
<thead>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-green">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-green">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td rowspan=2 class="bg-green">YYY</td>
</tr>
<tr>
<td class="bg-grey">&nbsp;</td>
</tr>
<tr>
<td colspan=2 class="bg-green">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white">&nbsp;</td>
</tr>
</tfoot>
</table>
<table id="third-table">
<thead>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-blue show-text">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-cyan show-text">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td rowspan=2 class="bg-blue show-text">YYY</td>
</tr>
<tr>
<td class="bg-green">XXX</td>
</tr>
<tr>
<td colspan=2 class="bg-cyan show-text">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
<table id="fourth-table">
<thead>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</thead>
<tbody>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white" rowspan=2>YYY</td>
</tr>
<tr>
<td class="bg-cyan show-text">XXX</td>
</tr>
<tr>
<td class="bg-white" colspan=2>XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="bg-white">XXX</td>
<td class="bg-white">YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<head>
<style>
body {
background-color: white;
margin: 0;
}
table {
background-color: red;
border-collapse: separate;
position: absolute;
top: 645px;
}
thead {
background-color: pink;
}
tbody {
background-color: grey;
}
tfoot {
background-color: orange;
}
tr {
background-color: green;
}
td:first-child {
background-color: cyan;
}
td {
background-color: blue;
border-style: solid;
border-width: 5px;
border-color: gold;
}
colgroup {
background-color: purple;
}
col:first-child {
background-color: khaki;
}
.rel {
position: relative;
bottom: 215px;
}
</style>
</head>
<body>
<table>
<colgroup>
<col>
<col>
</colgroup>
<thead class="rel">
<tr>
<td class="rel">XXX</td>
<td class="rel">YYY</td>
</tr>
</thead>
<tbody class="rel">
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
<tr>
<td>XXX</td>
<td rowspan=2 class="rel">YYY</td>
</tr>
<tr class="rel">
<td class="rel">XXX</td>
</tr>
<tr>
<td colspan=2 class="rel">XXX</td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="rel">XXX</td>
<td>YYY</td>
</tr>
</tfoot>
</table>
</body>

View File

@ -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

View File

@ -298,6 +298,7 @@ GetMetricsFor(nsPresContext* aPresContext,
nsRefPtr<nsFontMetrics> fm;
aPresContext->DeviceContext()->GetMetricsFor(font,
aStyleFont->mLanguage,
aStyleFont->mExplicitLanguage,
orientation,
fs, tp, *getter_AddRefs(fm));
return fm.forget();

View File

@ -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;
}

View File

@ -679,6 +679,7 @@ protected:
void PlaceChild(nsTableReflowState& aReflowState,
nsIFrame* aKidFrame,
nsPoint aKidPosition,
nsHTMLReflowMetrics& aKidDesiredSize,
const nsRect& aOriginalKidRect,
const nsRect& aOriginalKidVisualOverflow);

View File

@ -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());
}

View File

@ -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;

View File

@ -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<nsTableCellReflowState> 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!

View File

@ -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;

View File

@ -337,6 +337,7 @@ protected:
void PlaceChild(nsPresContext* aPresContext,
nsRowGroupReflowState& aReflowState,
nsIFrame* aKidFrame,
nsPoint aKidPosition,
nsHTMLReflowMetrics& aDesiredSize,
const nsRect& aOriginalKidRect,
const nsRect& aOriginalKidVisualOverflow);

View File

@ -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);

View File

@ -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 <stdbool.h>
#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 <malloc.h>
# define alloca _alloca
# else
# ifdef JEMALLOC_HAS_ALLOCA_H
# include <alloca.h>
# else
# include <stdlib.h>
# 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

View File

@ -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);
};

View File

@ -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', '')

View File

@ -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<nsCString>& 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<nsICryptoHash> cryptoHash = aCryptoHash;
if (!aCryptoHash) {
MOZ_ASSERT(!NS_IsMainThread(), "mCryptoHash must be used on worker thread");
cryptoHash = mCryptoHash;
}
Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_CL_CHECK_TIME> 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());
}
}

View File

@ -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<nsCString>& 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<nsCStringHashKey, int64_t> mTableFreshness;
uint32_t mFreshTime;
};
}

View File

@ -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();

View File

@ -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<nsICryptoHash> mCryptoHash;
nsAutoPtr<Classifier> 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<nsCString> 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<nsCString>::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<nsICryptoHash> 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<nsIObserverService> 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<nsIURI> 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<nsIUrlClassifierUtils> utilsService =
do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID);
rv = utilsService->GetKeyForURI(uri, key);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<LookupResultArray> 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,

View File

@ -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<nsICryptoHash> mCryptoHashMain;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsUrlClassifierDBService, NS_URLCLASSIFIERDBSERVICE_CID)

View File

@ -143,6 +143,15 @@ UrlClassifierDBServiceWorkerProxy::ResetDatabase()
return DispatchToWorkerThread(r);
}
NS_IMETHODIMP
UrlClassifierDBServiceWorkerProxy::OpenDb()
{
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableMethod(mTarget,
&nsIUrlClassifierDBServiceWorker::OpenDb);
return DispatchToWorkerThread(r);
}
NS_IMETHODIMP
UrlClassifierDBServiceWorkerProxy::CloseDb()
{