зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central a=merge CLOSED TREE
This commit is contained in:
Коммит
ab27d8e9b0
14
configure.in
14
configure.in
|
@ -1300,6 +1300,20 @@ if test -n "$MOZ_MSAN"; then
|
|||
fi
|
||||
AC_SUBST(MOZ_MSAN)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use Thread Sanitizer
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(thread-sanitizer,
|
||||
[ --enable-thread-sanitizer Enable Thread Sanitizer (default=no)],
|
||||
MOZ_TSAN=1,
|
||||
MOZ_TSAN= )
|
||||
if test -n "$MOZ_TSAN"; then
|
||||
MOZ_LLVM_HACKS=1
|
||||
AC_DEFINE(MOZ_TSAN)
|
||||
MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
|
||||
fi
|
||||
AC_SUBST(MOZ_TSAN)
|
||||
|
||||
# The LLVM symbolizer is used by all sanitizers
|
||||
AC_SUBST(LLVM_SYMBOLIZER)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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) &&
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
(new Function("return (function o() {}).caller;"))();
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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 ԰ world
|
||||
</body>
|
||||
</html>
|
|
@ -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>԰</i> world
|
||||
</body>
|
||||
</html>
|
|
@ -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>԰</em> world
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -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 ԰ world
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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"> </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"> </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>
|
|
@ -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>
|
|
@ -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"> </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"> </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>
|
|
@ -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>
|
|
@ -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"> </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"> </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>
|
|
@ -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>
|
|
@ -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"> </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"> </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>
|
|
@ -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>
|
|
@ -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"> </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"> </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>
|
|
@ -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>
|
|
@ -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"> </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"> </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>
|
|
@ -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>
|
|
@ -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"> </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"> </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>
|
|
@ -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>
|
|
@ -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"> </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"> </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>
|
|
@ -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>
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -679,6 +679,7 @@ protected:
|
|||
|
||||
void PlaceChild(nsTableReflowState& aReflowState,
|
||||
nsIFrame* aKidFrame,
|
||||
nsPoint aKidPosition,
|
||||
nsHTMLReflowMetrics& aKidDesiredSize,
|
||||
const nsRect& aOriginalKidRect,
|
||||
const nsRect& aOriginalKidVisualOverflow);
|
||||
|
|
|
@ -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());
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -337,6 +337,7 @@ protected:
|
|||
void PlaceChild(nsPresContext* aPresContext,
|
||||
nsRowGroupReflowState& aReflowState,
|
||||
nsIFrame* aKidFrame,
|
||||
nsPoint aKidPosition,
|
||||
nsHTMLReflowMetrics& aDesiredSize,
|
||||
const nsRect& aOriginalKidRect,
|
||||
const nsRect& aOriginalKidVisualOverflow);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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', '')
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче