mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-31 21:21:08 +00:00
Merge
This commit is contained in:
commit
bc461689df
@ -102,7 +102,7 @@ nsCOMPtr<nsINode> nsEventShell::sEventTargetNode;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsAccEventQueue::nsAccEventQueue(nsDocAccessible *aDocument):
|
||||
mProcessingStarted(PR_FALSE), mDocument(aDocument), mFlushingEventsCount(0)
|
||||
mObservingRefresh(PR_FALSE), mDocument(aDocument)
|
||||
{
|
||||
}
|
||||
|
||||
@ -157,6 +157,13 @@ nsAccEventQueue::Push(nsAccEvent *aEvent)
|
||||
void
|
||||
nsAccEventQueue::Shutdown()
|
||||
{
|
||||
if (mObservingRefresh) {
|
||||
nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
|
||||
if (!shell ||
|
||||
shell->RemoveRefreshObserver(this, Flush_Display)) {
|
||||
mObservingRefresh = PR_FALSE;
|
||||
}
|
||||
}
|
||||
mDocument = nsnull;
|
||||
mEvents.Clear();
|
||||
}
|
||||
@ -169,14 +176,19 @@ nsAccEventQueue::PrepareFlush()
|
||||
{
|
||||
// If there are pending events in the queue and events flush isn't planed
|
||||
// yet start events flush asynchronously.
|
||||
if (mEvents.Length() > 0 && !mProcessingStarted) {
|
||||
NS_DISPATCH_RUNNABLEMETHOD(Flush, this)
|
||||
mProcessingStarted = PR_TRUE;
|
||||
if (mEvents.Length() > 0 && !mObservingRefresh) {
|
||||
nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
|
||||
// Use a Flush_Display observer so that it will get called after
|
||||
// style and ayout have been flushed.
|
||||
if (shell &&
|
||||
shell->AddRefreshObserver(this, Flush_Display)) {
|
||||
mObservingRefresh = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::Flush()
|
||||
nsAccEventQueue::WillRefresh(mozilla::TimeStamp aTime)
|
||||
{
|
||||
// If the document accessible is now shut down, don't fire events in it
|
||||
// anymore.
|
||||
@ -187,42 +199,31 @@ nsAccEventQueue::Flush()
|
||||
if (!presShell)
|
||||
return;
|
||||
|
||||
// Flush layout so that all the frame construction, reflow, and styles are
|
||||
// up-to-date. This will ensure we can get frames for the related nodes, as
|
||||
// well as get the most current information for calculating things like
|
||||
// visibility. We don't flush the display because we don't care about
|
||||
// painting. If no flush is necessary the method will simple return.
|
||||
presShell->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
// Process only currently queued events. Newly appended events during events
|
||||
// flushing won't be processed.
|
||||
mFlushingEventsCount = mEvents.Length();
|
||||
NS_ASSERTION(mFlushingEventsCount,
|
||||
"How did we get here without events to fire?");
|
||||
nsTArray < nsRefPtr<nsAccEvent> > events;
|
||||
events.SwapElements(mEvents);
|
||||
PRUint32 length = events.Length();
|
||||
NS_ASSERTION(length, "How did we get here without events to fire?");
|
||||
|
||||
for (PRUint32 index = 0; index < mFlushingEventsCount; index ++) {
|
||||
for (PRUint32 index = 0; index < length; index ++) {
|
||||
|
||||
// No presshell means the document was shut down during event handling
|
||||
// by AT.
|
||||
if (!mDocument || !mDocument->HasWeakShell())
|
||||
break;
|
||||
|
||||
nsAccEvent *accEvent = mEvents[index];
|
||||
nsAccEvent *accEvent = events[index];
|
||||
if (accEvent->mEventRule != nsAccEvent::eDoNotEmit)
|
||||
mDocument->ProcessPendingEvent(accEvent);
|
||||
}
|
||||
|
||||
// Mark we are ready to start event processing again.
|
||||
mProcessingStarted = PR_FALSE;
|
||||
|
||||
// If the document accessible is alive then remove processed events from the
|
||||
// queue (otherwise they were removed on shutdown already) and reinitialize
|
||||
// queue processing callback if necessary (new events might occur duiring
|
||||
// delayed event processing).
|
||||
if (mDocument && mDocument->HasWeakShell()) {
|
||||
mEvents.RemoveElementsAt(0, mFlushingEventsCount);
|
||||
mFlushingEventsCount = 0;
|
||||
PrepareFlush();
|
||||
if (mEvents.Length() == 0) {
|
||||
nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
|
||||
if (!shell ||
|
||||
shell->RemoveRefreshObserver(this, Flush_Display)) {
|
||||
mObservingRefresh = PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,7 +242,7 @@ nsAccEventQueue::CoalesceEvents()
|
||||
switch(tailEvent->mEventRule) {
|
||||
case nsAccEvent::eCoalesceFromSameSubtree:
|
||||
{
|
||||
for (PRInt32 index = tail - 1; index >= mFlushingEventsCount; index--) {
|
||||
for (PRInt32 index = tail - 1; index >= 0; index--) {
|
||||
nsAccEvent* thisEvent = mEvents[index];
|
||||
|
||||
if (thisEvent->mEventType != tailEvent->mEventType)
|
||||
@ -365,7 +366,7 @@ nsAccEventQueue::CoalesceEvents()
|
||||
// Do not emit thisEvent, also apply this result to sibling nodes of
|
||||
// thisNode.
|
||||
thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
ApplyToSiblings(mFlushingEventsCount, index, thisEvent->mEventType,
|
||||
ApplyToSiblings(0, index, thisEvent->mEventType,
|
||||
thisEvent->mNode, nsAccEvent::eDoNotEmit);
|
||||
continue;
|
||||
}
|
||||
@ -386,7 +387,7 @@ nsAccEventQueue::CoalesceEvents()
|
||||
// Used for focus event, coalesce more older event since focus event
|
||||
// for accessible can be duplicated by event for its document, we are
|
||||
// interested in focus event for accessible.
|
||||
for (PRInt32 index = tail - 1; index >= mFlushingEventsCount; index--) {
|
||||
for (PRInt32 index = tail - 1; index >= 0; index--) {
|
||||
nsAccEvent* thisEvent = mEvents[index];
|
||||
if (thisEvent->mEventType == tailEvent->mEventType &&
|
||||
thisEvent->mEventRule == tailEvent->mEventRule &&
|
||||
@ -401,7 +402,7 @@ nsAccEventQueue::CoalesceEvents()
|
||||
{
|
||||
// Check for repeat events, coalesce newly appended event by more older
|
||||
// event.
|
||||
for (PRInt32 index = tail - 1; index >= mFlushingEventsCount; index--) {
|
||||
for (PRInt32 index = tail - 1; index >= 0; index--) {
|
||||
nsAccEvent* accEvent = mEvents[index];
|
||||
if (accEvent->mEventType == tailEvent->mEventType &&
|
||||
accEvent->mEventRule == tailEvent->mEventRule &&
|
||||
|
@ -45,6 +45,8 @@
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
#include "nsRefreshDriver.h"
|
||||
|
||||
class nsIPersistentProperties;
|
||||
|
||||
/**
|
||||
@ -90,7 +92,8 @@ private:
|
||||
/**
|
||||
* Event queue.
|
||||
*/
|
||||
class nsAccEventQueue : public nsISupports
|
||||
class nsAccEventQueue : public nsISupports,
|
||||
public nsARefreshObserver
|
||||
{
|
||||
public:
|
||||
nsAccEventQueue(nsDocAccessible *aDocument);
|
||||
@ -120,9 +123,7 @@ private:
|
||||
* Process pending events. It calls nsDocAccessible::ProcessPendingEvent()
|
||||
* where the real event processing is happen.
|
||||
*/
|
||||
void Flush();
|
||||
|
||||
NS_DECL_RUNNABLEMETHOD(nsAccEventQueue, Flush)
|
||||
virtual void WillRefresh(mozilla::TimeStamp aTime);
|
||||
|
||||
/**
|
||||
* Coalesce redundant events from the queue.
|
||||
@ -157,9 +158,10 @@ private:
|
||||
nsAccEvent *aDescendantAccEvent);
|
||||
|
||||
/**
|
||||
* Indicates whether events flush is run.
|
||||
* Indicates whether we're waiting on a refresh notification from our
|
||||
* presshell to flush events
|
||||
*/
|
||||
PRBool mProcessingStarted;
|
||||
PRBool mObservingRefresh;
|
||||
|
||||
/**
|
||||
* The document accessible reference owning this queue.
|
||||
@ -167,13 +169,8 @@ private:
|
||||
nsRefPtr<nsDocAccessible> mDocument;
|
||||
|
||||
/**
|
||||
* The number of events processed currently. Used to avoid event coalescence
|
||||
* with new events appended to the queue because of events handling.
|
||||
*/
|
||||
PRInt32 mFlushingEventsCount;
|
||||
|
||||
/**
|
||||
* Pending events array.
|
||||
* Pending events array. Don't make this an nsAutoTArray; we use
|
||||
* SwapElements() on it.
|
||||
*/
|
||||
nsTArray<nsRefPtr<nsAccEvent> > mEvents;
|
||||
};
|
||||
|
@ -42,6 +42,41 @@
|
||||
|
||||
#include "nsIContent.h"
|
||||
|
||||
// Element-specific flags
|
||||
enum {
|
||||
// Set if the element has a pending style change.
|
||||
ELEMENT_HAS_PENDING_RESTYLE = (1 << NODE_TYPE_SPECIFIC_BITS_OFFSET),
|
||||
|
||||
// Set if the element is a potential restyle root (that is, has a style
|
||||
// change pending _and_ that style change will attempt to restyle
|
||||
// descendants).
|
||||
ELEMENT_IS_POTENTIAL_RESTYLE_ROOT =
|
||||
(1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET + 1)),
|
||||
|
||||
// Set if the element has a pending animation style change.
|
||||
ELEMENT_HAS_PENDING_ANIMATION_RESTYLE =
|
||||
(1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET + 2)),
|
||||
|
||||
// Set if the element is a potential animation restyle root (that is,
|
||||
// has an animation style change pending _and_ that style change
|
||||
// will attempt to restyle descendants).
|
||||
ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT =
|
||||
(1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET + 3)),
|
||||
|
||||
// All of those bits together, for convenience.
|
||||
ELEMENT_ALL_RESTYLE_FLAGS = ELEMENT_HAS_PENDING_RESTYLE |
|
||||
ELEMENT_IS_POTENTIAL_RESTYLE_ROOT |
|
||||
ELEMENT_HAS_PENDING_ANIMATION_RESTYLE |
|
||||
ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT,
|
||||
|
||||
// Just the HAS_PENDING bits, for convenience
|
||||
ELEMENT_PENDING_RESTYLE_FLAGS = ELEMENT_HAS_PENDING_RESTYLE |
|
||||
ELEMENT_HAS_PENDING_ANIMATION_RESTYLE,
|
||||
|
||||
// Remaining bits are for subclasses
|
||||
ELEMENT_TYPE_SPECIFIC_BITS_OFFSET = NODE_TYPE_SPECIFIC_BITS_OFFSET + 4
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -178,16 +178,26 @@ enum {
|
||||
// Set if the node has the accesskey attribute set.
|
||||
NODE_HAS_NAME = 0x00800000U,
|
||||
|
||||
// Four bits for the script-type ID
|
||||
// Two bits for the script-type ID. Not enough to represent all
|
||||
// nsIProgrammingLanguage values, but we don't care. In practice,
|
||||
// we can represent the ones we want, and we can fail the others at
|
||||
// runtime.
|
||||
NODE_SCRIPT_TYPE_OFFSET = 24,
|
||||
|
||||
NODE_SCRIPT_TYPE_SIZE = 4,
|
||||
NODE_SCRIPT_TYPE_SIZE = 2,
|
||||
|
||||
NODE_SCRIPT_TYPE_MASK = (1 << NODE_SCRIPT_TYPE_SIZE) - 1,
|
||||
|
||||
// Remaining bits are node type specific.
|
||||
NODE_TYPE_SPECIFIC_BITS_OFFSET =
|
||||
NODE_SCRIPT_TYPE_OFFSET + NODE_SCRIPT_TYPE_SIZE
|
||||
};
|
||||
|
||||
PR_STATIC_ASSERT(PRUint32(nsIProgrammingLanguage::JAVASCRIPT) <=
|
||||
PRUint32(NODE_SCRIPT_TYPE_MASK));
|
||||
PR_STATIC_ASSERT(PRUint32(nsIProgrammingLanguage::PYTHON) <=
|
||||
PRUint32(NODE_SCRIPT_TYPE_MASK));
|
||||
|
||||
// Useful inline function for getting a node given an nsIContent and an
|
||||
// nsIDocument. Returns the first argument cast to nsINode if it is non-null,
|
||||
// otherwise returns the second (which may be null). We use type variables
|
||||
|
@ -70,6 +70,9 @@
|
||||
// This bit is set to indicate that the text may be part of a selection.
|
||||
#define NS_TEXT_IN_SELECTION (1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET + 2))
|
||||
|
||||
// Make sure we have enough space for those bits
|
||||
PR_STATIC_ASSERT(NODE_TYPE_SPECIFIC_BITS_OFFSET + 2 < 32);
|
||||
|
||||
class nsIDOMAttr;
|
||||
class nsIDOMEventListener;
|
||||
class nsIDOMNodeList;
|
||||
|
@ -2882,7 +2882,9 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
// Unset this flag since we now really are in a document.
|
||||
UnsetFlags(NODE_FORCE_XBL_BINDINGS |
|
||||
// And clear the lazy frame construction bits.
|
||||
NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
|
||||
NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES |
|
||||
// And the restyle bits
|
||||
ELEMENT_ALL_RESTYLE_FLAGS);
|
||||
}
|
||||
|
||||
// If NODE_FORCE_XBL_BINDINGS was set we might have anonymous children
|
||||
@ -3481,14 +3483,13 @@ nsGenericElement::GetScriptTypeID() const
|
||||
{
|
||||
PtrBits flags = GetFlags();
|
||||
|
||||
/* 4 bits reserved for script-type ID. */
|
||||
return (flags >> NODE_SCRIPT_TYPE_OFFSET) & 0x000F;
|
||||
return (flags >> NODE_SCRIPT_TYPE_OFFSET) & NODE_SCRIPT_TYPE_MASK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericElement::SetScriptTypeID(PRUint32 aLang)
|
||||
{
|
||||
if ((aLang & 0x000F) != aLang) {
|
||||
if ((aLang & NODE_SCRIPT_TYPE_MASK) != aLang) {
|
||||
NS_ERROR("script ID too large!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -3105,8 +3105,10 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
|
||||
PRUint32 sfeFlags = nsLayoutUtils::SFE_WANT_FIRST_FRAME;
|
||||
nsLayoutUtils::SurfaceFromElementResult res =
|
||||
nsLayoutUtils::SurfaceFromElement(imgElt, sfeFlags);
|
||||
if (!res.mSurface)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
if (!res.mSurface) {
|
||||
// Spec says to silently do nothing if the element is still loading.
|
||||
return res.mIsStillLoading ? NS_OK : NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
#ifndef WINCE
|
||||
// On non-CE, force a copy if we're using drawImage with our destination
|
||||
|
@ -65,6 +65,7 @@ _TEST_FILES_0 = \
|
||||
image_green.png \
|
||||
image_green-redirect \
|
||||
image_green-redirect^headers^ \
|
||||
test_drawImageIncomplete.html \
|
||||
$(NULL)
|
||||
|
||||
# xor and lighter aren't well handled by cairo; they mostly work, but we don't want
|
||||
|
60
content/canvas/test/test_drawImageIncomplete.html
Normal file
60
content/canvas/test/test_drawImageIncomplete.html
Normal file
@ -0,0 +1,60 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=517056
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 517056</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=517056">Mozilla Bug 517056</a>
|
||||
<p id="display">
|
||||
<canvas id="c" width="1" height="1"></canvas>
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 517056 **/
|
||||
var ctx = $("c").getContext('2d');
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillRect(0, 0, 1, 1);
|
||||
var data = ctx.getImageData(0, 0, 1, 1).data;
|
||||
is(data[0], 0, "Red channel of black should be 0");
|
||||
is(data[1], 0, "Green channel of black should be 0");
|
||||
is(data[2], 0, "Blue channel of black should be 0")
|
||||
is(data[3], 255, "Alpha channel of black should be opaque");
|
||||
var img = new Image();
|
||||
// Force a new URI every time, so that we don't run into stupid caching issues.
|
||||
img.src = "image_green-1x1.png?" + (new Date + 0) + Math.random();
|
||||
// This shouldn't throw
|
||||
ctx.drawImage(img, 0, 0);
|
||||
var data = ctx.getImageData(0, 0, 1, 1).data;
|
||||
is(data[0], 0, "Red channel of black should be 0 and image should have been ignored");
|
||||
is(data[1], 0, "Green channel of black should be 0 and image should have been ignored");
|
||||
is(data[2], 0, "Blue channel of black should be 0 and image should have been ignored")
|
||||
is(data[3], 255, "Alpha channel of black should be opaque and image should have been ignored");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
img.onload = function() {
|
||||
ctx.drawImage(img, 0, 0);
|
||||
var data = ctx.getImageData(0, 0, 1, 1).data;
|
||||
is(data[0], 0, "Red channel of green should be 0");
|
||||
is(data[1], 255, "Green channel of green should be 255");
|
||||
is(data[2], 0, "Blue channel of green should be 0")
|
||||
is(data[3], 255, "Alpha channel of green should be opaque");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -886,17 +886,20 @@ protected:
|
||||
// added ourselves to our mForm. It's possible to have a non-null mForm, but
|
||||
// not have this flag set. That happens when the form is set via the content
|
||||
// sink.
|
||||
#define ADDED_TO_FORM (1 << NODE_TYPE_SPECIFIC_BITS_OFFSET)
|
||||
#define ADDED_TO_FORM (1 << ELEMENT_TYPE_SPECIFIC_BITS_OFFSET)
|
||||
|
||||
// If this flag is set on an nsGenericHTMLFormElement, that means that its form
|
||||
// is in the process of being unbound from the tree, and this form element
|
||||
// hasn't re-found its form in nsGenericHTMLFormElement::UnbindFromTree yet.
|
||||
#define MAYBE_ORPHAN_FORM_ELEMENT (1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET+1))
|
||||
#define MAYBE_ORPHAN_FORM_ELEMENT (1 << (ELEMENT_TYPE_SPECIFIC_BITS_OFFSET+1))
|
||||
|
||||
// NOTE: I don't think it's possible to have the above two flags set at the
|
||||
// same time, so if it becomes an issue we can probably merge them into the
|
||||
// same bit. --bz
|
||||
|
||||
// Make sure we have enough space for those bits
|
||||
PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
@ -1939,6 +1939,15 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace)
|
||||
}
|
||||
}
|
||||
|
||||
// Flag us as not being able to start layout until we hit <body>
|
||||
// or scripts that require layout, so that we won't run into FOUC
|
||||
// issues. We need to do that before making the Stop() call,
|
||||
// since if we have no frame yet the flush Stop() triggers might
|
||||
// try to create one for us, and we don't want our presshell
|
||||
// starting layout if that happens. But we don't want to do this
|
||||
// before the PermitUnload call above.
|
||||
mMayStartLayout = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(shell));
|
||||
webnav->Stop(nsIWebNavigation::STOP_NETWORK);
|
||||
|
||||
@ -1947,6 +1956,10 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace)
|
||||
// document again otherwise the document could have a non-zero onload block
|
||||
// count without the onload blocker request being in the loadgroup.
|
||||
EnsureOnloadBlocker();
|
||||
} else {
|
||||
// See comment before the mMayStartLayout set in the other branch
|
||||
// of this if.
|
||||
mMayStartLayout = PR_FALSE;
|
||||
}
|
||||
|
||||
// The open occurred after the document finished loading.
|
||||
|
@ -449,7 +449,10 @@ public:
|
||||
|
||||
*/
|
||||
|
||||
#define XUL_ELEMENT_TEMPLATE_GENERATED 1 << NODE_TYPE_SPECIFIC_BITS_OFFSET
|
||||
#define XUL_ELEMENT_TEMPLATE_GENERATED (1 << ELEMENT_TYPE_SPECIFIC_BITS_OFFSET)
|
||||
|
||||
// Make sure we have space for our bit
|
||||
PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET < 32);
|
||||
|
||||
class nsScriptEventHandlerOwnerTearoff;
|
||||
|
||||
|
@ -91,6 +91,7 @@ EXPORTS = \
|
||||
CPPSRCS = \
|
||||
FrameLayerBuilder.cpp \
|
||||
FramePropertyTable.cpp \
|
||||
RestyleTracker.cpp \
|
||||
nsCSSColorUtils.cpp \
|
||||
nsCSSFrameConstructor.cpp \
|
||||
nsCSSRendering.cpp \
|
||||
|
315
layout/base/RestyleTracker.cpp
Normal file
315
layout/base/RestyleTracker.cpp
Normal file
@ -0,0 +1,315 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Boris Zbarsky <bzbarsky@mit.edu> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "RestyleTracker.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsStyleChangeList.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
||||
inline nsIDocument*
|
||||
RestyleTracker::Document() const {
|
||||
return mFrameConstructor->mDocument;
|
||||
}
|
||||
|
||||
#define RESTYLE_ARRAY_STACKSIZE 128
|
||||
|
||||
struct LaterSiblingCollector {
|
||||
RestyleTracker* tracker;
|
||||
nsTArray< nsRefPtr<dom::Element> >* elements;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
CollectLaterSiblings(nsISupports* aElement,
|
||||
RestyleTracker::RestyleData& aData,
|
||||
void* aSiblingCollector)
|
||||
{
|
||||
dom::Element* element =
|
||||
static_cast<dom::Element*>(aElement);
|
||||
LaterSiblingCollector* collector =
|
||||
static_cast<LaterSiblingCollector*>(aSiblingCollector);
|
||||
// Only collect the entries that actually need restyling by us (and
|
||||
// haven't, for example, already been restyled).
|
||||
// It's important to not mess with the flags on entries not in our
|
||||
// document.
|
||||
if (element->GetCurrentDoc() == collector->tracker->Document() &&
|
||||
element->HasFlag(collector->tracker->RestyleBit()) &&
|
||||
(aData.mRestyleHint & eRestyle_LaterSiblings)) {
|
||||
collector->elements->AppendElement(element);
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
struct RestyleCollector {
|
||||
RestyleTracker* tracker;
|
||||
RestyleTracker::RestyleEnumerateData** restyleArrayPtr;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
CollectRestyles(nsISupports* aElement,
|
||||
RestyleTracker::RestyleData& aData,
|
||||
void* aRestyleCollector)
|
||||
{
|
||||
dom::Element* element =
|
||||
static_cast<dom::Element*>(aElement);
|
||||
RestyleCollector* collector =
|
||||
static_cast<RestyleCollector*>(aRestyleCollector);
|
||||
// Only collect the entries that actually need restyling by us (and
|
||||
// haven't, for example, already been restyled).
|
||||
// It's important to not mess with the flags on entries not in our
|
||||
// document.
|
||||
if (element->GetCurrentDoc() != collector->tracker->Document() ||
|
||||
!element->HasFlag(collector->tracker->RestyleBit())) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!element->HasFlag(collector->tracker->RootBit()) ||
|
||||
// Maybe we're just not reachable via the frame tree?
|
||||
(element->GetFlattenedTreeParent() &&
|
||||
!element->GetFlattenedTreeParent()->GetPrimaryFrame()) ||
|
||||
// Or not reachable due to an async reinsert we have
|
||||
// pending? If so, we'll have a reframe hint around.
|
||||
// That incidentally makes it safe that we still have
|
||||
// the bit, since any descendants that didn't get added
|
||||
// to the roots list because we had the bits will be
|
||||
// completely restyled in a moment.
|
||||
(aData.mChangeHint & nsChangeHint_ReconstructFrame),
|
||||
"Why did this not get handled while processing mRestyleRoots?");
|
||||
|
||||
// Unset the restyle bits now, so if they get readded later as we
|
||||
// process we won't clobber that adding of the bit.
|
||||
element->UnsetFlags(collector->tracker->RestyleBit() |
|
||||
collector->tracker->RootBit());
|
||||
|
||||
RestyleTracker::RestyleEnumerateData** restyleArrayPtr =
|
||||
collector->restyleArrayPtr;
|
||||
RestyleTracker::RestyleEnumerateData* currentRestyle =
|
||||
*restyleArrayPtr;
|
||||
currentRestyle->mElement = element;
|
||||
currentRestyle->mRestyleHint = aData.mRestyleHint;
|
||||
currentRestyle->mChangeHint = aData.mChangeHint;
|
||||
|
||||
// Increment to the next slot in the array
|
||||
*restyleArrayPtr = currentRestyle + 1;
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
inline void
|
||||
RestyleTracker::ProcessOneRestyle(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aChangeHint)
|
||||
{
|
||||
NS_PRECONDITION((aRestyleHint & eRestyle_LaterSiblings) == 0,
|
||||
"Someone should have handled this before calling us");
|
||||
NS_PRECONDITION(aElement->GetCurrentDoc() == mFrameConstructor->mDocument,
|
||||
"Element has unexpected document");
|
||||
|
||||
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
|
||||
if (aRestyleHint & (eRestyle_Self | eRestyle_Subtree)) {
|
||||
mFrameConstructor->RestyleElement(aElement, primaryFrame, aChangeHint,
|
||||
*this,
|
||||
(aRestyleHint & eRestyle_Subtree) != 0);
|
||||
} else if (aChangeHint &&
|
||||
(primaryFrame ||
|
||||
(aChangeHint & nsChangeHint_ReconstructFrame))) {
|
||||
// Don't need to recompute style; just apply the hint
|
||||
nsStyleChangeList changeList;
|
||||
changeList.AppendChange(primaryFrame, aElement, aChangeHint);
|
||||
mFrameConstructor->ProcessRestyledFrames(changeList);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RestyleTracker::ProcessRestyles()
|
||||
{
|
||||
// Make sure to not rebuild quote or counter lists while we're
|
||||
// processing restyles
|
||||
mFrameConstructor->BeginUpdate();
|
||||
|
||||
// loop so that we process any restyle events generated by processing
|
||||
while (mPendingRestyles.Count()) {
|
||||
if (mHaveLaterSiblingRestyles) {
|
||||
// Convert them to individual restyles on all the later siblings
|
||||
nsAutoTArray<nsRefPtr<Element>, RESTYLE_ARRAY_STACKSIZE> laterSiblingArr;
|
||||
LaterSiblingCollector siblingCollector = { this, &laterSiblingArr };
|
||||
mPendingRestyles.Enumerate(CollectLaterSiblings, &siblingCollector);
|
||||
for (PRUint32 i = 0; i < laterSiblingArr.Length(); ++i) {
|
||||
Element* element = laterSiblingArr[i];
|
||||
for (nsIContent* sibling = element->GetNextSibling();
|
||||
sibling;
|
||||
sibling = sibling->GetNextSibling()) {
|
||||
if (sibling->IsElement() &&
|
||||
AddPendingRestyle(sibling->AsElement(), eRestyle_Subtree,
|
||||
NS_STYLE_HINT_NONE)) {
|
||||
// Nothing else to do here; we'll handle the following
|
||||
// siblings when we get to |sibling| in laterSiblingArr.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now remove all those eRestyle_LaterSiblings bits
|
||||
for (PRUint32 i = 0; i < laterSiblingArr.Length(); ++i) {
|
||||
Element* element = laterSiblingArr[i];
|
||||
NS_ASSERTION(element->HasFlag(RestyleBit()), "How did that happen?");
|
||||
RestyleData data;
|
||||
#ifdef DEBUG
|
||||
PRBool found =
|
||||
#endif
|
||||
mPendingRestyles.Get(element, &data);
|
||||
NS_ASSERTION(found, "Where did our entry go?");
|
||||
data.mRestyleHint =
|
||||
nsRestyleHint(data.mRestyleHint & ~eRestyle_LaterSiblings);
|
||||
|
||||
mPendingRestyles.Put(element, data);
|
||||
}
|
||||
|
||||
mHaveLaterSiblingRestyles = PR_FALSE;
|
||||
}
|
||||
|
||||
PRUint32 rootCount;
|
||||
while ((rootCount = mRestyleRoots.Length())) {
|
||||
// Make sure to pop the element off our restyle root array, so
|
||||
// that we can freely append to the array as we process this
|
||||
// element.
|
||||
nsRefPtr<Element> element;
|
||||
element.swap(mRestyleRoots[rootCount - 1]);
|
||||
mRestyleRoots.RemoveElementAt(rootCount - 1);
|
||||
|
||||
// Do the document check before calling GetRestyleData, since we
|
||||
// don't want to do the sibling-processing GetRestyleData does if
|
||||
// the node is no longer relevant.
|
||||
if (element->GetCurrentDoc() != mFrameConstructor->mDocument) {
|
||||
// Content node has been removed from our document; nothing else
|
||||
// to do here
|
||||
continue;
|
||||
}
|
||||
|
||||
RestyleData data;
|
||||
if (!GetRestyleData(element, &data)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ProcessOneRestyle(element, data.mRestyleHint, data.mChangeHint);
|
||||
}
|
||||
|
||||
if (mHaveLaterSiblingRestyles) {
|
||||
// Keep processing restyles for now
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now we only have entries with change hints left. To be safe in
|
||||
// case of reentry from the handing of the change hint, use a
|
||||
// scratch array instead of calling out to ProcessOneRestyle while
|
||||
// enumerating the hashtable. Use the stack if we can, otherwise
|
||||
// fall back on heap-allocation.
|
||||
nsAutoTArray<RestyleEnumerateData, RESTYLE_ARRAY_STACKSIZE> restyleArr;
|
||||
RestyleEnumerateData* restylesToProcess =
|
||||
restyleArr.AppendElements(mPendingRestyles.Count());
|
||||
if (restylesToProcess) {
|
||||
RestyleEnumerateData* lastRestyle = restylesToProcess;
|
||||
RestyleCollector collector = { this, &lastRestyle };
|
||||
mPendingRestyles.Enumerate(CollectRestyles, &collector);
|
||||
|
||||
// Clear the hashtable now that we don't need it anymore
|
||||
mPendingRestyles.Clear();
|
||||
|
||||
for (RestyleEnumerateData* currentRestyle = restylesToProcess;
|
||||
currentRestyle != lastRestyle;
|
||||
++currentRestyle) {
|
||||
ProcessOneRestyle(currentRestyle->mElement,
|
||||
currentRestyle->mRestyleHint,
|
||||
currentRestyle->mChangeHint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set mInStyleRefresh to false now, since the EndUpdate call might
|
||||
// add more restyles.
|
||||
mFrameConstructor->mInStyleRefresh = PR_FALSE;
|
||||
|
||||
mFrameConstructor->EndUpdate();
|
||||
|
||||
#ifdef DEBUG
|
||||
mFrameConstructor->mPresShell->VerifyStyleTree();
|
||||
#endif
|
||||
}
|
||||
|
||||
PRBool
|
||||
RestyleTracker::GetRestyleData(Element* aElement, RestyleData* aData)
|
||||
{
|
||||
NS_PRECONDITION(aElement->GetCurrentDoc() == mFrameConstructor->mDocument,
|
||||
"Unexpected document; this will lead to incorrect behavior!");
|
||||
|
||||
if (!aElement->HasFlag(RestyleBit())) {
|
||||
NS_ASSERTION(!aElement->HasFlag(RootBit()), "Bogus root bit?");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
PRBool gotData =
|
||||
#endif
|
||||
mPendingRestyles.Get(aElement, aData);
|
||||
NS_ASSERTION(gotData, "Must have data if restyle bit is set");
|
||||
|
||||
if (aData->mRestyleHint & eRestyle_LaterSiblings) {
|
||||
// Someone readded the eRestyle_LaterSiblings hint for this
|
||||
// element. Leave it around for now, but remove the other restyle
|
||||
// hints and the change hint for it. Also unset its root bit,
|
||||
// since it's no longer a root with the new restyle data.
|
||||
RestyleData newData;
|
||||
newData.mChangeHint = nsChangeHint(0);
|
||||
newData.mRestyleHint = eRestyle_LaterSiblings;
|
||||
mPendingRestyles.Put(aElement, newData);
|
||||
aElement->UnsetFlags(RootBit());
|
||||
aData->mRestyleHint =
|
||||
nsRestyleHint(aData->mRestyleHint & ~eRestyle_LaterSiblings);
|
||||
} else {
|
||||
mPendingRestyles.Remove(aElement);
|
||||
aElement->UnsetFlags(mRestyleBits);
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
237
layout/base/RestyleTracker.h
Normal file
237
layout/base/RestyleTracker.h
Normal file
@ -0,0 +1,237 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Boris Zbarsky <bzbarsky@mit.edu> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#ifndef mozilla_css_RestyleTracker_h
|
||||
#define mozilla_css_RestyleTracker_h
|
||||
|
||||
/**
|
||||
* A class which manages pending restyles. This handles keeping track
|
||||
* of what nodes restyles need to happen on and so forth.
|
||||
*/
|
||||
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsIFrame.h"
|
||||
|
||||
class nsCSSFrameConstructor;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
||||
class RestyleTracker {
|
||||
public:
|
||||
typedef mozilla::dom::Element Element;
|
||||
|
||||
RestyleTracker(PRUint32 aRestyleBits,
|
||||
nsCSSFrameConstructor* aFrameConstructor) :
|
||||
mRestyleBits(aRestyleBits), mFrameConstructor(aFrameConstructor),
|
||||
mHaveLaterSiblingRestyles(PR_FALSE)
|
||||
{
|
||||
NS_PRECONDITION((mRestyleBits & ~ELEMENT_ALL_RESTYLE_FLAGS) == 0,
|
||||
"Why do we have these bits set?");
|
||||
NS_PRECONDITION((mRestyleBits & ELEMENT_PENDING_RESTYLE_FLAGS) != 0,
|
||||
"Must have a restyle flag");
|
||||
NS_PRECONDITION((mRestyleBits & ELEMENT_PENDING_RESTYLE_FLAGS) !=
|
||||
ELEMENT_PENDING_RESTYLE_FLAGS,
|
||||
"Shouldn't have both restyle flags set");
|
||||
NS_PRECONDITION((mRestyleBits & ~ELEMENT_PENDING_RESTYLE_FLAGS) != 0,
|
||||
"Must have root flag");
|
||||
NS_PRECONDITION((mRestyleBits & ~ELEMENT_PENDING_RESTYLE_FLAGS) !=
|
||||
(ELEMENT_ALL_RESTYLE_FLAGS & ~ELEMENT_PENDING_RESTYLE_FLAGS),
|
||||
"Shouldn't have both root flags");
|
||||
}
|
||||
|
||||
PRBool Init() {
|
||||
return mPendingRestyles.Init();
|
||||
}
|
||||
|
||||
PRUint32 Count() const {
|
||||
return mPendingRestyles.Count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a restyle for the given element to the tracker. Returns true
|
||||
* if the element already had eRestyle_LaterSiblings set on it.
|
||||
*/
|
||||
PRBool AddPendingRestyle(Element* aElement, nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint);
|
||||
|
||||
/**
|
||||
* Process the restyles we've been tracking.
|
||||
*/
|
||||
void ProcessRestyles();
|
||||
|
||||
// Return our ELEMENT_HAS_PENDING_(ANIMATION_)RESTYLE bit
|
||||
PRUint32 RestyleBit() const {
|
||||
return mRestyleBits & ELEMENT_PENDING_RESTYLE_FLAGS;
|
||||
}
|
||||
|
||||
// Return our ELEMENT_IS_POTENTIAL_(ANIMATION_)RESTYLE_ROOT bit
|
||||
PRUint32 RootBit() const {
|
||||
return mRestyleBits & ~ELEMENT_PENDING_RESTYLE_FLAGS;
|
||||
}
|
||||
|
||||
struct RestyleData {
|
||||
nsRestyleHint mRestyleHint; // What we want to restyle
|
||||
nsChangeHint mChangeHint; // The minimal change hint for "self"
|
||||
};
|
||||
|
||||
/**
|
||||
* If the given Element has a restyle pending for it, return the
|
||||
* relevant restyle data. This function will clear everything other
|
||||
* than a possible eRestyle_LaterSiblings hint for aElement out of
|
||||
* our hashtable. The returned aData will never have an
|
||||
* eRestyle_LaterSiblings hint in it.
|
||||
*
|
||||
* The return value indicates whether any restyle data was found for
|
||||
* the element. If false is returned, then the state of *aData is
|
||||
* undefined.
|
||||
*/
|
||||
PRBool GetRestyleData(Element* aElement, RestyleData* aData);
|
||||
|
||||
/**
|
||||
* The document we're associated with.
|
||||
*/
|
||||
inline nsIDocument* Document() const;
|
||||
|
||||
struct RestyleEnumerateData : public RestyleData {
|
||||
nsCOMPtr<Element> mElement;
|
||||
};
|
||||
|
||||
private:
|
||||
/**
|
||||
* Handle a single mPendingRestyles entry. aRestyleHint must not
|
||||
* include eRestyle_LaterSiblings; that needs to be dealt with
|
||||
* before calling this function.
|
||||
*/
|
||||
inline void ProcessOneRestyle(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aChangeHint);
|
||||
|
||||
typedef nsDataHashtable<nsISupportsHashKey, RestyleData> PendingRestyleTable;
|
||||
typedef nsAutoTArray< nsRefPtr<Element>, 32> RestyleRootArray;
|
||||
// Our restyle bits. These will be a subset of ELEMENT_ALL_RESTYLE_FLAGS, and
|
||||
// will include one flag from ELEMENT_PENDING_RESTYLE_FLAGS and one flag
|
||||
// that's not in ELEMENT_PENDING_RESTYLE_FLAGS.
|
||||
PRUint32 mRestyleBits;
|
||||
nsCSSFrameConstructor* mFrameConstructor; // Owns us
|
||||
// A hashtable that maps elements to RestyleData structs. The
|
||||
// values only make sense if the element's current document is our
|
||||
// document and it has our RestyleBit() flag set. In particular,
|
||||
// said bit might not be set if the element had a restyle posted and
|
||||
// then was moved around in the DOM.
|
||||
PendingRestyleTable mPendingRestyles;
|
||||
// An array that keeps track of our possible restyle roots. This
|
||||
// maintains the invariant that if A and B are both restyle roots
|
||||
// and A is an ancestor of B then A will come after B in the array.
|
||||
// We maintain this invariant by checking whether an element has an
|
||||
// ancestor with the restyle root bit set before appending it to the
|
||||
// array.
|
||||
RestyleRootArray mRestyleRoots;
|
||||
// True if we have some entries with the eRestyle_LaterSiblings
|
||||
// flag. We need this to avoid enumerating the hashtable looking
|
||||
// for such entries when we can't possibly have any.
|
||||
PRBool mHaveLaterSiblingRestyles;
|
||||
};
|
||||
|
||||
inline PRBool RestyleTracker::AddPendingRestyle(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint)
|
||||
{
|
||||
RestyleData existingData;
|
||||
existingData.mRestyleHint = nsRestyleHint(0);
|
||||
existingData.mChangeHint = NS_STYLE_HINT_NONE;
|
||||
|
||||
// Check the RestyleBit() flag before doing the hashtable Get, since
|
||||
// it's possible that the data in the hashtable isn't actually
|
||||
// relevant anymore (if the flag is not set).
|
||||
if (aElement->HasFlag(RestyleBit())) {
|
||||
mPendingRestyles.Get(aElement, &existingData);
|
||||
} else {
|
||||
aElement->SetFlags(RestyleBit());
|
||||
}
|
||||
|
||||
PRBool hadRestyleLaterSiblings =
|
||||
(existingData.mRestyleHint & eRestyle_LaterSiblings) != 0;
|
||||
existingData.mRestyleHint =
|
||||
nsRestyleHint(existingData.mRestyleHint | aRestyleHint);
|
||||
NS_UpdateHint(existingData.mChangeHint, aMinChangeHint);
|
||||
|
||||
mPendingRestyles.Put(aElement, existingData);
|
||||
|
||||
// We can only treat this element as a restyle root if we would
|
||||
// actually restyle its descendants (so either call
|
||||
// ReResolveStyleContext on it or just reframe it).
|
||||
if ((aRestyleHint & (eRestyle_Self | eRestyle_Subtree)) ||
|
||||
(aMinChangeHint & nsChangeHint_ReconstructFrame)) {
|
||||
for (const Element* cur = aElement; !cur->HasFlag(RootBit()); ) {
|
||||
nsIContent* parent = cur->GetFlattenedTreeParent();
|
||||
// Stop if we have no parent or the parent is not an element or
|
||||
// we're part of the viewport scrollbars (because those are not
|
||||
// frametree descendants of the primary frame of the root
|
||||
// element).
|
||||
// XXXbz maybe the primary frame of the root should be the root scrollframe?
|
||||
if (!parent || !parent->IsElement() ||
|
||||
// If we've hit the root via a native anonymous kid and that
|
||||
// this native anonymous kid is not obviously a descendant
|
||||
// of the root's primary frame, assume we're under the root
|
||||
// scrollbars. Since those don't get reresolved when
|
||||
// reresolving the root, we need to make sure to add the
|
||||
// element to mRestyleRoots.
|
||||
(cur->IsInNativeAnonymousSubtree() && !parent->GetParent() &&
|
||||
cur->GetPrimaryFrame() &&
|
||||
cur->GetPrimaryFrame()->GetParent() != parent->GetPrimaryFrame())) {
|
||||
mRestyleRoots.AppendElement(aElement);
|
||||
break;
|
||||
}
|
||||
cur = parent->AsElement();
|
||||
}
|
||||
// At this point some ancestor of aElement (possibly aElement
|
||||
// itself) is in mRestyleRoots. Set the root bit on aElement, to
|
||||
// speed up searching for an existing root on its descendants.
|
||||
aElement->SetFlags(RootBit());
|
||||
}
|
||||
|
||||
mHaveLaterSiblingRestyles =
|
||||
mHaveLaterSiblingRestyles || (aRestyleHint & eRestyle_LaterSiblings) != 0;
|
||||
return hadRestyleLaterSiblings;
|
||||
}
|
||||
|
||||
} // namespace css
|
||||
} // namespacs mozilla
|
||||
|
||||
#endif /* mozilla_css_RestyleTracker_h */
|
@ -1397,6 +1397,10 @@ nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument *aDocument,
|
||||
, mInLazyFCRefresh(PR_FALSE)
|
||||
, mHoverGeneration(0)
|
||||
, mRebuildAllExtraHint(nsChangeHint(0))
|
||||
, mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE |
|
||||
ELEMENT_IS_POTENTIAL_RESTYLE_ROOT, this)
|
||||
, mPendingAnimationRestyles(ELEMENT_HAS_PENDING_ANIMATION_RESTYLE |
|
||||
ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT, this)
|
||||
{
|
||||
// XXXbz this should be in Init() or something!
|
||||
if (!mPendingRestyles.Init() || !mPendingAnimationRestyles.Init()) {
|
||||
@ -2333,6 +2337,14 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
|
||||
if (!mTempFrameTreeState)
|
||||
state.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState));
|
||||
|
||||
// Make sure that we'll handle restyles for this document element in
|
||||
// the future. We need this, because the document element might
|
||||
// have stale restyle bits from a previous frame constructor for
|
||||
// this document. Unlike in AddFrameConstructionItems, it's safe to
|
||||
// unset all element restyle flags, since we don't have any
|
||||
// siblings.
|
||||
aDocElement->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS);
|
||||
|
||||
// --------- CREATE AREA OR BOX FRAME -------
|
||||
nsRefPtr<nsStyleContext> styleContext;
|
||||
styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
|
||||
@ -5024,6 +5036,16 @@ nsCSSFrameConstructor::AddFrameConstructionItems(nsFrameConstructorState& aState
|
||||
FrameConstructionItemList& aItems)
|
||||
{
|
||||
aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
|
||||
if (aContent->IsElement()) {
|
||||
// We can't just remove our pending restyle flags, since we may
|
||||
// have restyle-later-siblings set on us. But we _can_ remove the
|
||||
// "is possible restyle root" flags, and need to. Otherwise we can
|
||||
// end up with stale such flags (e.g. if we used to have a
|
||||
// display:none parent when our last restyle was posted and
|
||||
// processed and now no longer do).
|
||||
aContent->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS &
|
||||
~ELEMENT_PENDING_RESTYLE_FLAGS);
|
||||
}
|
||||
|
||||
// don't create a whitespace frame if aParent doesn't want it
|
||||
if (!NeedFrameFor(aState, aParentFrame, aContent)) {
|
||||
@ -8079,7 +8101,9 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
|
||||
void
|
||||
nsCSSFrameConstructor::RestyleElement(Element *aElement,
|
||||
nsIFrame *aPrimaryFrame,
|
||||
nsChangeHint aMinHint)
|
||||
nsChangeHint aMinHint,
|
||||
RestyleTracker& aRestyleTracker,
|
||||
PRBool aRestyleDescendants)
|
||||
{
|
||||
NS_ASSERTION(aPrimaryFrame == aElement->GetPrimaryFrame(),
|
||||
"frame/content mismatch");
|
||||
@ -8096,7 +8120,8 @@ nsCSSFrameConstructor::RestyleElement(Element *aElement,
|
||||
} else if (aPrimaryFrame) {
|
||||
nsStyleChangeList changeList;
|
||||
mPresShell->FrameManager()->
|
||||
ComputeStyleChangeFor(aPrimaryFrame, &changeList, aMinHint);
|
||||
ComputeStyleChangeFor(aPrimaryFrame, &changeList, aMinHint,
|
||||
aRestyleTracker, aRestyleDescendants);
|
||||
ProcessRestyledFrames(changeList);
|
||||
} else {
|
||||
// no frames, reconstruct for content
|
||||
@ -8104,20 +8129,6 @@ nsCSSFrameConstructor::RestyleElement(Element *aElement,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSFrameConstructor::RestyleLaterSiblings(Element *aElement)
|
||||
{
|
||||
for (nsIContent* sibling = aElement->GetNextSibling();
|
||||
sibling;
|
||||
sibling = sibling->GetNextSibling()) {
|
||||
if (!sibling->IsElement())
|
||||
continue;
|
||||
|
||||
RestyleElement(sibling->AsElement(), sibling->GetPrimaryFrame(),
|
||||
NS_STYLE_HINT_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSFrameConstructor::ContentStatesChanged(nsIContent* aContent1,
|
||||
nsIContent* aContent2,
|
||||
@ -9633,7 +9644,13 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
|
||||
iter != last;
|
||||
++iter) {
|
||||
PRInt32 i = iter.XBLInvolved() ? -1 : iter.position();
|
||||
AddFrameConstructionItems(aState, *iter, i, aFrame, itemsToConstruct);
|
||||
nsIContent* child = *iter;
|
||||
// Frame construction item construction should not post
|
||||
// restyles, so removing restyle flags here is safe.
|
||||
if (child->IsElement()) {
|
||||
child->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS);
|
||||
}
|
||||
AddFrameConstructionItems(aState, child, i, aFrame, itemsToConstruct);
|
||||
}
|
||||
itemsToConstruct.SetParentHasNoXBLChildren(!iter.XBLInvolved());
|
||||
|
||||
@ -10957,6 +10974,13 @@ nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState,
|
||||
content->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
|
||||
continue;
|
||||
}
|
||||
if (content->IsElement()) {
|
||||
// See comment explaining why we need to remove the "is possible
|
||||
// restyle root" flags in AddFrameConstructionItems. But note
|
||||
// that we can remove all restyle flags, just like in
|
||||
// ProcessChildren and for the same reason.
|
||||
content->UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS);
|
||||
}
|
||||
|
||||
nsRefPtr<nsStyleContext> childContext =
|
||||
ResolveStyleContext(parentStyleContext, content);
|
||||
@ -11333,9 +11357,8 @@ void
|
||||
nsCSSFrameConstructor::RestyleForEmptyChange(Element* aContainer)
|
||||
{
|
||||
// In some cases (:empty + E, :empty ~ E), a change if the content of
|
||||
// an element requires restyling its grandparent, because it changes
|
||||
// its parent's :empty state.
|
||||
nsRestyleHint hint = eRestyle_Self;
|
||||
// an element requires restyling its parent's siblings.
|
||||
nsRestyleHint hint = eRestyle_Subtree;
|
||||
nsIContent* grandparent = aContainer->GetParent();
|
||||
if (grandparent &&
|
||||
(grandparent->GetFlags() & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS)) {
|
||||
@ -11385,7 +11408,7 @@ nsCSSFrameConstructor::RestyleForAppend(Element* aContainer,
|
||||
}
|
||||
|
||||
if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
|
||||
PostRestyleEvent(aContainer, eRestyle_Self, NS_STYLE_HINT_NONE);
|
||||
PostRestyleEvent(aContainer, eRestyle_Subtree, NS_STYLE_HINT_NONE);
|
||||
// Restyling the container is the most we can do here, so we're done.
|
||||
return;
|
||||
}
|
||||
@ -11396,7 +11419,7 @@ nsCSSFrameConstructor::RestyleForAppend(Element* aContainer,
|
||||
cur;
|
||||
cur = cur->GetPreviousSibling()) {
|
||||
if (cur->IsElement()) {
|
||||
PostRestyleEvent(cur->AsElement(), eRestyle_Self, NS_STYLE_HINT_NONE);
|
||||
PostRestyleEvent(cur->AsElement(), eRestyle_Subtree, NS_STYLE_HINT_NONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -11404,17 +11427,20 @@ nsCSSFrameConstructor::RestyleForAppend(Element* aContainer,
|
||||
}
|
||||
|
||||
// Needed since we can't use PostRestyleEvent on non-elements (with
|
||||
// eRestyle_LaterSiblings or nsRestyleHint(eRestyle_Self |
|
||||
// eRestyle_LaterSiblings or nsRestyleHint(eRestyle_Subtree |
|
||||
// eRestyle_LaterSiblings) as appropriate).
|
||||
static void
|
||||
RestyleSiblingsStartingWith(nsCSSFrameConstructor *aFrameConstructor,
|
||||
nsIContent *aStartingSibling /* may be null */)
|
||||
{
|
||||
if (aStartingSibling) {
|
||||
nsIContent* parent = aStartingSibling->GetParent();
|
||||
if (parent && parent->IsElement()) {
|
||||
aFrameConstructor->PostRestyleEvent(parent->AsElement(), eRestyle_Self,
|
||||
NS_STYLE_HINT_NONE);
|
||||
for (nsIContent *sibling = aStartingSibling; sibling;
|
||||
sibling = sibling->GetNextSibling()) {
|
||||
if (sibling->IsElement()) {
|
||||
aFrameConstructor->
|
||||
PostRestyleEvent(sibling->AsElement(),
|
||||
nsRestyleHint(eRestyle_Subtree | eRestyle_LaterSiblings),
|
||||
NS_STYLE_HINT_NONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11460,7 +11486,7 @@ nsCSSFrameConstructor::RestyleForInsertOrChange(Element* aContainer,
|
||||
}
|
||||
|
||||
if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
|
||||
PostRestyleEvent(aContainer, eRestyle_Self, NS_STYLE_HINT_NONE);
|
||||
PostRestyleEvent(aContainer, eRestyle_Subtree, NS_STYLE_HINT_NONE);
|
||||
// Restyling the container is the most we can do here, so we're done.
|
||||
return;
|
||||
}
|
||||
@ -11482,7 +11508,7 @@ nsCSSFrameConstructor::RestyleForInsertOrChange(Element* aContainer,
|
||||
}
|
||||
if (content->IsElement()) {
|
||||
if (passedChild) {
|
||||
PostRestyleEvent(content->AsElement(), eRestyle_Self,
|
||||
PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
|
||||
NS_STYLE_HINT_NONE);
|
||||
}
|
||||
break;
|
||||
@ -11499,7 +11525,7 @@ nsCSSFrameConstructor::RestyleForInsertOrChange(Element* aContainer,
|
||||
}
|
||||
if (content->IsElement()) {
|
||||
if (passedChild) {
|
||||
PostRestyleEvent(content->AsElement(), eRestyle_Self,
|
||||
PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
|
||||
NS_STYLE_HINT_NONE);
|
||||
}
|
||||
break;
|
||||
@ -11542,7 +11568,7 @@ nsCSSFrameConstructor::RestyleForRemove(Element* aContainer,
|
||||
}
|
||||
|
||||
if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
|
||||
PostRestyleEvent(aContainer, eRestyle_Self, NS_STYLE_HINT_NONE);
|
||||
PostRestyleEvent(aContainer, eRestyle_Subtree, NS_STYLE_HINT_NONE);
|
||||
// Restyling the container is the most we can do here, so we're done.
|
||||
return;
|
||||
}
|
||||
@ -11564,7 +11590,7 @@ nsCSSFrameConstructor::RestyleForRemove(Element* aContainer,
|
||||
}
|
||||
if (content->IsElement()) {
|
||||
if (reachedFollowingSibling) {
|
||||
PostRestyleEvent(content->AsElement(), eRestyle_Self,
|
||||
PostRestyleEvent(content->AsElement(), eRestyle_Subtree,
|
||||
NS_STYLE_HINT_NONE);
|
||||
}
|
||||
break;
|
||||
@ -11577,7 +11603,7 @@ nsCSSFrameConstructor::RestyleForRemove(Element* aContainer,
|
||||
content = content->GetPreviousSibling()) {
|
||||
if (content->IsElement()) {
|
||||
if (reachedFollowingSibling) {
|
||||
PostRestyleEvent(content->AsElement(), eRestyle_Self, NS_STYLE_HINT_NONE);
|
||||
PostRestyleEvent(content->AsElement(), eRestyle_Subtree, NS_STYLE_HINT_NONE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -11589,59 +11615,6 @@ nsCSSFrameConstructor::RestyleForRemove(Element* aContainer,
|
||||
}
|
||||
|
||||
|
||||
static PLDHashOperator
|
||||
CollectRestyles(nsISupports* aElement,
|
||||
nsCSSFrameConstructor::RestyleData& aData,
|
||||
void* aRestyleArrayPtr)
|
||||
{
|
||||
nsCSSFrameConstructor::RestyleEnumerateData** restyleArrayPtr =
|
||||
static_cast<nsCSSFrameConstructor::RestyleEnumerateData**>
|
||||
(aRestyleArrayPtr);
|
||||
nsCSSFrameConstructor::RestyleEnumerateData* currentRestyle =
|
||||
*restyleArrayPtr;
|
||||
currentRestyle->mElement = static_cast<Element*>(aElement);
|
||||
currentRestyle->mRestyleHint = aData.mRestyleHint;
|
||||
currentRestyle->mChangeHint = aData.mChangeHint;
|
||||
|
||||
// Increment to the next slot in the array
|
||||
*restyleArrayPtr = currentRestyle + 1;
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSFrameConstructor::ProcessOneRestyle(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aChangeHint)
|
||||
{
|
||||
NS_PRECONDITION(aElement, "Must have element");
|
||||
|
||||
if (!aElement->IsInDoc() ||
|
||||
aElement->GetCurrentDoc() != mDocument) {
|
||||
// Content node has been removed from our document; nothing else
|
||||
// to do here
|
||||
return;
|
||||
}
|
||||
|
||||
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
|
||||
if (aRestyleHint & eRestyle_Self) {
|
||||
RestyleElement(aElement, primaryFrame, aChangeHint);
|
||||
} else if (aChangeHint &&
|
||||
(primaryFrame ||
|
||||
(aChangeHint & nsChangeHint_ReconstructFrame))) {
|
||||
// Don't need to recompute style; just apply the hint
|
||||
nsStyleChangeList changeList;
|
||||
changeList.AppendChange(primaryFrame, aElement, aChangeHint);
|
||||
ProcessRestyledFrames(changeList);
|
||||
}
|
||||
|
||||
if (aRestyleHint & eRestyle_LaterSiblings) {
|
||||
RestyleLaterSiblings(aElement);
|
||||
}
|
||||
}
|
||||
|
||||
#define RESTYLE_ARRAY_STACKSIZE 128
|
||||
|
||||
void
|
||||
nsCSSFrameConstructor::RebuildAllStyleData(nsChangeHint aExtraHint)
|
||||
{
|
||||
@ -11686,8 +11659,10 @@ nsCSSFrameConstructor::RebuildAllStyleData(nsChangeHint aExtraHint)
|
||||
nsStyleChangeList changeList;
|
||||
// XXX Does it matter that we're passing aExtraHint to the real root
|
||||
// frame and not the root node's primary frame?
|
||||
// Note: The restyle tracker we pass in here doesn't matter.
|
||||
mPresShell->FrameManager()->ComputeStyleChangeFor(mPresShell->GetRootFrame(),
|
||||
&changeList, aExtraHint);
|
||||
&changeList, aExtraHint,
|
||||
mPendingRestyles, PR_TRUE);
|
||||
// Process the required changes
|
||||
ProcessRestyledFrames(changeList);
|
||||
// Tell the style set it's safe to destroy the old rule tree. We
|
||||
@ -11699,58 +11674,6 @@ nsCSSFrameConstructor::RebuildAllStyleData(nsChangeHint aExtraHint)
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSFrameConstructor::ProcessPendingRestyleTable(
|
||||
nsDataHashtable<nsISupportsHashKey, RestyleData>& aRestyles)
|
||||
{
|
||||
PRUint32 count = aRestyles.Count();
|
||||
|
||||
// Make sure to not rebuild quote or counter lists while we're
|
||||
// processing restyles
|
||||
BeginUpdate();
|
||||
|
||||
// loop so that we process any restyle events generated by processing
|
||||
while (count) {
|
||||
// Use the stack if we can, otherwise fall back on heap-allocation.
|
||||
nsAutoTArray<RestyleEnumerateData, RESTYLE_ARRAY_STACKSIZE> restyleArr;
|
||||
RestyleEnumerateData* restylesToProcess = restyleArr.AppendElements(count);
|
||||
|
||||
if (!restylesToProcess) {
|
||||
return;
|
||||
}
|
||||
|
||||
RestyleEnumerateData* lastRestyle = restylesToProcess;
|
||||
aRestyles.Enumerate(CollectRestyles, &lastRestyle);
|
||||
|
||||
NS_ASSERTION(lastRestyle - restylesToProcess == PRInt32(count),
|
||||
"Enumeration screwed up somehow");
|
||||
|
||||
// Clear the hashtable so we don't end up trying to process a restyle we're
|
||||
// already processing, sending us into an infinite loop.
|
||||
aRestyles.Clear();
|
||||
|
||||
for (RestyleEnumerateData* currentRestyle = restylesToProcess;
|
||||
currentRestyle != lastRestyle;
|
||||
++currentRestyle) {
|
||||
ProcessOneRestyle(currentRestyle->mElement,
|
||||
currentRestyle->mRestyleHint,
|
||||
currentRestyle->mChangeHint);
|
||||
}
|
||||
|
||||
count = aRestyles.Count();
|
||||
}
|
||||
|
||||
// Set mInStyleRefresh to false now, since the EndUpdate call might
|
||||
// add more restyles.
|
||||
mInStyleRefresh = PR_FALSE;
|
||||
|
||||
EndUpdate();
|
||||
|
||||
#ifdef DEBUG
|
||||
mPresShell->VerifyStyleTree();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSFrameConstructor::ProcessPendingRestyles()
|
||||
{
|
||||
@ -11764,7 +11687,7 @@ nsCSSFrameConstructor::ProcessPendingRestyles()
|
||||
"Nesting calls to ProcessPendingRestyles?");
|
||||
presContext->SetProcessingRestyles(PR_TRUE);
|
||||
|
||||
ProcessPendingRestyleTable(mPendingRestyles);
|
||||
mPendingRestyles.ProcessRestyles();
|
||||
|
||||
#ifdef DEBUG
|
||||
PRUint32 oldPendingRestyleCount = mPendingRestyles.Count();
|
||||
@ -11779,7 +11702,7 @@ nsCSSFrameConstructor::ProcessPendingRestyles()
|
||||
// the running transition so it can check for a new change on the same
|
||||
// property, and then posts an immediate animation style change).
|
||||
presContext->SetProcessingAnimationStyleChange(PR_TRUE);
|
||||
ProcessPendingRestyleTable(mPendingAnimationRestyles);
|
||||
mPendingAnimationRestyles.ProcessRestyles();
|
||||
presContext->SetProcessingAnimationStyleChange(PR_FALSE);
|
||||
|
||||
presContext->SetProcessingRestyles(PR_FALSE);
|
||||
@ -11810,19 +11733,9 @@ nsCSSFrameConstructor::PostRestyleEventCommon(Element* aElement,
|
||||
return;
|
||||
}
|
||||
|
||||
RestyleData existingData;
|
||||
existingData.mRestyleHint = nsRestyleHint(0);
|
||||
existingData.mChangeHint = NS_STYLE_HINT_NONE;
|
||||
|
||||
nsDataHashtable<nsISupportsHashKey, RestyleData> &restyles =
|
||||
RestyleTracker& tracker =
|
||||
aForAnimation ? mPendingAnimationRestyles : mPendingRestyles;
|
||||
|
||||
restyles.Get(aElement, &existingData);
|
||||
existingData.mRestyleHint =
|
||||
nsRestyleHint(existingData.mRestyleHint | aRestyleHint);
|
||||
NS_UpdateHint(existingData.mChangeHint, aMinChangeHint);
|
||||
|
||||
restyles.Put(aElement, existingData);
|
||||
tracker.AddPendingRestyle(aElement, aRestyleHint, aMinChangeHint);
|
||||
|
||||
PostRestyleEventInternal(PR_FALSE);
|
||||
}
|
||||
@ -11835,8 +11748,7 @@ nsCSSFrameConstructor::PostRestyleEventInternal(PRBool aForLazyConstruction)
|
||||
// add ourselves as a refresh observer until then.
|
||||
PRBool inRefresh = aForLazyConstruction ? mInLazyFCRefresh : mInStyleRefresh;
|
||||
if (!mObservingRefreshDriver && !inRefresh) {
|
||||
mObservingRefreshDriver = mPresShell->GetPresContext()->
|
||||
RefreshDriver()->AddRefreshObserver(this, Flush_Style);
|
||||
mObservingRefreshDriver = mPresShell->AddRefreshObserver(this, Flush_Style);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11848,8 +11760,7 @@ nsCSSFrameConstructor::WillRefresh(mozilla::TimeStamp aTime)
|
||||
// a refresh so we don't restart due to animation-triggered
|
||||
// restyles. The actual work of processing our restyles will get
|
||||
// done when the refresh driver flushes styles.
|
||||
mPresShell->GetPresContext()->RefreshDriver()->
|
||||
RemoveRefreshObserver(this, Flush_Style);
|
||||
mPresShell->RemoveRefreshObserver(this, Flush_Style);
|
||||
mObservingRefreshDriver = PR_FALSE;
|
||||
mInLazyFCRefresh = PR_TRUE;
|
||||
mInStyleRefresh = PR_TRUE;
|
||||
|
@ -48,12 +48,12 @@
|
||||
#include "nsIXBLService.h"
|
||||
#include "nsQuoteList.h"
|
||||
#include "nsCounterManager.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsPageContentFrame.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "RestyleTracker.h"
|
||||
|
||||
class nsIDocument;
|
||||
struct nsFrameItems;
|
||||
@ -83,6 +83,7 @@ class nsCSSFrameConstructor : public nsARefreshObserver
|
||||
{
|
||||
public:
|
||||
typedef mozilla::dom::Element Element;
|
||||
typedef mozilla::css::RestyleTracker RestyleTracker;
|
||||
|
||||
nsCSSFrameConstructor(nsIDocument *aDocument, nsIPresShell* aPresShell);
|
||||
~nsCSSFrameConstructor(void) {
|
||||
@ -302,17 +303,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
// Note: It's the caller's responsibility to make sure to wrap a
|
||||
// ProcessOneRestyle call in a view update batch.
|
||||
// This function does not call ProcessAttachedQueue() on the binding manager.
|
||||
// If the caller wants that to happen synchronously, it needs to handle that
|
||||
// itself.
|
||||
void ProcessOneRestyle(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aChangeHint);
|
||||
|
||||
void ProcessPendingRestyleTable(
|
||||
nsDataHashtable<nsISupportsHashKey, RestyleData>& aRestyles);
|
||||
friend class mozilla::css::RestyleTracker;
|
||||
|
||||
void RestyleForEmptyChange(Element* aContainer);
|
||||
|
||||
@ -461,9 +452,9 @@ private:
|
||||
// XXXbz do we really need the aPrimaryFrame argument here?
|
||||
void RestyleElement(Element* aElement,
|
||||
nsIFrame* aPrimaryFrame,
|
||||
nsChangeHint aMinHint);
|
||||
|
||||
void RestyleLaterSiblings(Element* aElement);
|
||||
nsChangeHint aMinHint,
|
||||
RestyleTracker& aRestyleTracker,
|
||||
PRBool aRestyleDescendants);
|
||||
|
||||
nsresult InitAndRestoreFrame (const nsFrameConstructorState& aState,
|
||||
nsIContent* aContent,
|
||||
@ -1837,15 +1828,6 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
struct RestyleData {
|
||||
nsRestyleHint mRestyleHint; // What we want to restyle
|
||||
nsChangeHint mChangeHint; // The minimal change hint for "self"
|
||||
};
|
||||
|
||||
struct RestyleEnumerateData : public RestyleData {
|
||||
nsCOMPtr<Element> mElement;
|
||||
};
|
||||
|
||||
friend class nsFrameConstructorState;
|
||||
|
||||
private:
|
||||
@ -1910,8 +1892,8 @@ private:
|
||||
|
||||
nsCOMPtr<nsILayoutHistoryState> mTempFrameTreeState;
|
||||
|
||||
nsDataHashtable<nsISupportsHashKey, RestyleData> mPendingRestyles;
|
||||
nsDataHashtable<nsISupportsHashKey, RestyleData> mPendingAnimationRestyles;
|
||||
RestyleTracker mPendingRestyles;
|
||||
RestyleTracker mPendingAnimationRestyles;
|
||||
|
||||
static nsIXBLService * gXBLService;
|
||||
};
|
||||
|
@ -139,13 +139,14 @@ inline PRBool NS_IsHintSubset(nsChangeHint aSubset, nsChangeHint aSuperSet) {
|
||||
nsChangeHint(NS_STYLE_HINT_REFLOW | nsChangeHint_ReconstructFrame)
|
||||
|
||||
/**
|
||||
* |nsRestyleHint| is a bitfield for the result of |HasStateDependentStyle|
|
||||
* and |HasAttributeDependentStyle|. All values have an implied "and
|
||||
* descendants." When no restyling is necessary, use |nsRestyleHint(0)|.
|
||||
* |nsRestyleHint| is a bitfield for the result of
|
||||
* |HasStateDependentStyle| and |HasAttributeDependentStyle|. When no
|
||||
* restyling is necessary, use |nsRestyleHint(0)|.
|
||||
*/
|
||||
enum nsRestyleHint {
|
||||
eRestyle_Self = 0x1,
|
||||
eRestyle_LaterSiblings = 0x2
|
||||
eRestyle_Subtree = 0x2, /* self and descendants */
|
||||
eRestyle_LaterSiblings = 0x4 /* implies "and descendants" */
|
||||
};
|
||||
|
||||
|
||||
|
@ -91,6 +91,7 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "nsTransitionManager.h"
|
||||
#include "RestyleTracker.h"
|
||||
|
||||
#include "nsFrameManager.h"
|
||||
#ifdef ACCESSIBILITY
|
||||
@ -961,7 +962,9 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
nsIContent *aParentContent,
|
||||
nsStyleChangeList *aChangeList,
|
||||
nsChangeHint aMinChange,
|
||||
PRBool aFireAccessibilityEvents)
|
||||
nsRestyleHint aRestyleHint,
|
||||
PRBool aFireAccessibilityEvents,
|
||||
RestyleTracker& aRestyleTracker)
|
||||
{
|
||||
if (!NS_IsHintSubset(nsChangeHint_NeedDirtyReflow, aMinChange)) {
|
||||
// If aMinChange doesn't include nsChangeHint_NeedDirtyReflow, clear out
|
||||
@ -980,7 +983,7 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
aMinChange =
|
||||
NS_SubtractHint(aMinChange, nsChangeHint_ClearAncestorIntrinsics);
|
||||
}
|
||||
|
||||
|
||||
// It would be nice if we could make stronger assertions here; they
|
||||
// would let us simplify the ?: expressions below setting |content|
|
||||
// and |pseudoContent| in sensible ways as well as making what
|
||||
@ -1021,6 +1024,22 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
// comment above assertion at start of function.)
|
||||
nsIContent* content = localContent ? localContent : aParentContent;
|
||||
|
||||
if (content && content->IsElement()) {
|
||||
RestyleTracker::RestyleData restyleData;
|
||||
if (aRestyleTracker.GetRestyleData(content->AsElement(), &restyleData)) {
|
||||
if (NS_UpdateHint(aMinChange, restyleData.mChangeHint)) {
|
||||
aChangeList->AppendChange(aFrame, content, restyleData.mChangeHint);
|
||||
}
|
||||
aRestyleHint = nsRestyleHint(aRestyleHint | restyleData.mRestyleHint);
|
||||
}
|
||||
}
|
||||
|
||||
nsRestyleHint childRestyleHint = aRestyleHint;
|
||||
|
||||
if (childRestyleHint == eRestyle_Self) {
|
||||
childRestyleHint = nsRestyleHint(0);
|
||||
}
|
||||
|
||||
nsStyleContext* parentContext;
|
||||
nsIFrame* resolvedChild = nsnull;
|
||||
// Get the frame providing the parent style context. If it is a
|
||||
@ -1049,7 +1068,8 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
// frame because it is visible or hidden withitn this frame.
|
||||
assumeDifferenceHint = ReResolveStyleContext(aPresContext, providerFrame,
|
||||
aParentContent, aChangeList,
|
||||
aMinChange, PR_FALSE);
|
||||
aMinChange, aRestyleHint,
|
||||
PR_FALSE, aRestyleTracker);
|
||||
|
||||
// The provider's new context becomes the parent context of
|
||||
// aFrame's context.
|
||||
@ -1099,6 +1119,9 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
// continuation).
|
||||
newContext = prevContinuationContext;
|
||||
}
|
||||
else if (!aRestyleHint) {
|
||||
newContext = styleSet->ReparentStyleContext(oldContext, parentContext);
|
||||
}
|
||||
else if (pseudoTag == nsCSSAnonBoxes::mozNonElement) {
|
||||
NS_ASSERTION(localContent,
|
||||
"non pseudo-element frame without content node");
|
||||
@ -1135,7 +1158,7 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
nsCSSPseudoElements::ePseudo_PseudoElementCount,
|
||||
"Unexpected pseudo type");
|
||||
if (pseudoTag == nsCSSPseudoElements::firstLetter) {
|
||||
NS_ASSERTION(aFrame->GetType() == nsGkAtoms::letterFrame,
|
||||
NS_ASSERTION(aFrame->GetType() == nsGkAtoms::letterFrame,
|
||||
"firstLetter pseudoTag without a nsFirstLetterFrame");
|
||||
nsBlockFrame* block = nsBlockFrame::GetNearestAncestorBlock(aFrame);
|
||||
pseudoContent = block->GetContent();
|
||||
@ -1150,6 +1173,7 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
"non pseudo-element frame without content node");
|
||||
newContext = styleSet->ResolveStyleFor(content->AsElement(), parentContext);
|
||||
}
|
||||
|
||||
NS_ASSERTION(newContext, "failed to get new style context");
|
||||
if (newContext) {
|
||||
if (!parentContext) {
|
||||
@ -1184,7 +1208,9 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
newContext = oldContext; // new context failed, recover...
|
||||
}
|
||||
|
||||
// do additional contexts
|
||||
// do additional contexts
|
||||
// XXXbz might be able to avoid selector matching here in some
|
||||
// cases; won't worry about it for now.
|
||||
PRInt32 contextIndex = -1;
|
||||
while (1 == 1) {
|
||||
nsStyleContext* oldExtraContext = nsnull;
|
||||
@ -1253,8 +1279,22 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
NS_ASSERTION(!undisplayed->mStyle->GetPseudo(),
|
||||
"Shouldn't have random pseudo style contexts in the "
|
||||
"undisplayed map");
|
||||
nsRefPtr<nsStyleContext> undisplayedContext =
|
||||
styleSet->ResolveStyleFor(undisplayed->mContent->AsElement(), newContext);
|
||||
nsRestyleHint thisChildHint = childRestyleHint;
|
||||
RestyleTracker::RestyleData undisplayedRestyleData;
|
||||
if (aRestyleTracker.GetRestyleData(undisplayed->mContent->AsElement(),
|
||||
&undisplayedRestyleData)) {
|
||||
thisChildHint =
|
||||
nsRestyleHint(thisChildHint | undisplayedRestyleData.mRestyleHint);
|
||||
}
|
||||
nsRefPtr<nsStyleContext> undisplayedContext;
|
||||
if (thisChildHint) {
|
||||
undisplayedContext =
|
||||
styleSet->ResolveStyleFor(undisplayed->mContent->AsElement(),
|
||||
newContext);
|
||||
} else {
|
||||
undisplayedContext =
|
||||
styleSet->ReparentStyleContext(undisplayed->mStyle, newContext);
|
||||
}
|
||||
if (undisplayedContext) {
|
||||
const nsStyleDisplay* display = undisplayedContext->GetStyleDisplay();
|
||||
if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
|
||||
@ -1272,7 +1312,11 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
|
||||
// Check whether we might need to create a new ::before frame.
|
||||
// There's no need to do this if we're planning to reframe already
|
||||
// or if we're not forcing restyles on kids.
|
||||
if (!(aMinChange & nsChangeHint_ReconstructFrame) &&
|
||||
childRestyleHint) {
|
||||
// Make sure not to do this for pseudo-frames -- those can't have :before
|
||||
// or :after content. Neither can non-elements or leaf frames.
|
||||
if (!pseudoTag && localContent && localContent->IsElement() &&
|
||||
@ -1296,8 +1340,11 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!(aMinChange & nsChangeHint_ReconstructFrame)) {
|
||||
// Check whether we might need to create a new ::after frame.
|
||||
// There's no need to do this if we're planning to reframe already
|
||||
// or if we're not forcing restyles on kids.
|
||||
if (!(aMinChange & nsChangeHint_ReconstructFrame) &&
|
||||
childRestyleHint) {
|
||||
// Make sure not to do this for pseudo-frames -- those can't have :before
|
||||
// or :after content. Neither can non-elements or leaf frames.
|
||||
if (!pseudoTag && localContent && localContent->IsElement() &&
|
||||
@ -1390,19 +1437,25 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
content, aChangeList,
|
||||
NS_SubtractHint(aMinChange,
|
||||
nsChangeHint_ReflowFrame),
|
||||
fireAccessibilityEvents);
|
||||
childRestyleHint,
|
||||
fireAccessibilityEvents,
|
||||
aRestyleTracker);
|
||||
|
||||
// reresolve placeholder's context under the same parent
|
||||
// as the out-of-flow frame
|
||||
ReResolveStyleContext(aPresContext, child, content,
|
||||
aChangeList, aMinChange,
|
||||
fireAccessibilityEvents);
|
||||
childRestyleHint,
|
||||
fireAccessibilityEvents,
|
||||
aRestyleTracker);
|
||||
}
|
||||
else { // regular child frame
|
||||
if (child != resolvedChild) {
|
||||
ReResolveStyleContext(aPresContext, child, content,
|
||||
aChangeList, aMinChange,
|
||||
fireAccessibilityEvents);
|
||||
childRestyleHint,
|
||||
fireAccessibilityEvents,
|
||||
aRestyleTracker);
|
||||
} else {
|
||||
NOISY_TRACE_FRAME("child frame already resolved as descendant, skipping",aFrame);
|
||||
}
|
||||
@ -1424,7 +1477,9 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
void
|
||||
nsFrameManager::ComputeStyleChangeFor(nsIFrame *aFrame,
|
||||
nsStyleChangeList *aChangeList,
|
||||
nsChangeHint aMinChange)
|
||||
nsChangeHint aMinChange,
|
||||
RestyleTracker& aRestyleTracker,
|
||||
PRBool aRestyleDescendants)
|
||||
{
|
||||
if (aMinChange) {
|
||||
aChangeList->AppendChange(aFrame, aFrame->GetContent(), aMinChange);
|
||||
@ -1449,7 +1504,11 @@ nsFrameManager::ComputeStyleChangeFor(nsIFrame *aFrame,
|
||||
// Inner loop over next-in-flows of the current frame
|
||||
nsChangeHint frameChange =
|
||||
ReResolveStyleContext(GetPresContext(), frame, nsnull,
|
||||
aChangeList, topLevelChange, PR_TRUE);
|
||||
aChangeList, topLevelChange,
|
||||
aRestyleDescendants ?
|
||||
eRestyle_Subtree : eRestyle_Self,
|
||||
PR_TRUE,
|
||||
aRestyleTracker);
|
||||
NS_UpdateHint(topLevelChange, frameChange);
|
||||
|
||||
if (topLevelChange & nsChangeHint_ReconstructFrame) {
|
||||
|
@ -57,6 +57,12 @@
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsFrameManagerBase.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
class RestyleTracker;
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
/**
|
||||
* Frame manager interface. The frame manager serves two purposes:
|
||||
* <li>provides a service for mapping from content to frame and from
|
||||
@ -70,6 +76,8 @@
|
||||
|
||||
class nsFrameManager : public nsFrameManagerBase
|
||||
{
|
||||
typedef mozilla::css::RestyleTracker RestyleTracker;
|
||||
|
||||
public:
|
||||
nsFrameManager() NS_HIDDEN;
|
||||
~nsFrameManager() NS_HIDDEN;
|
||||
@ -151,7 +159,9 @@ public:
|
||||
NS_HIDDEN_(void)
|
||||
ComputeStyleChangeFor(nsIFrame* aFrame,
|
||||
nsStyleChangeList* aChangeList,
|
||||
nsChangeHint aMinChange);
|
||||
nsChangeHint aMinChange,
|
||||
RestyleTracker& aRestyleTracker,
|
||||
PRBool aRestyleDescendants);
|
||||
|
||||
/*
|
||||
* Capture/restore frame state for the frame subtree rooted at aFrame.
|
||||
@ -192,13 +202,20 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
// Use eRestyle_Self for the aRestyleHint argument to mean
|
||||
// "reresolve our style context but not kids", use eRestyle_Subtree
|
||||
// to mean "reresolve our style context and kids", and use
|
||||
// nsRestyleHint(0) to mean recompute a new style context for our
|
||||
// current parent and existing rulenode, and the same for kids.
|
||||
NS_HIDDEN_(nsChangeHint)
|
||||
ReResolveStyleContext(nsPresContext *aPresContext,
|
||||
nsIFrame *aFrame,
|
||||
nsIContent *aParentContent,
|
||||
nsStyleChangeList *aChangeList,
|
||||
nsChangeHint aMinChange,
|
||||
PRBool aFireAccessibilityEvents);
|
||||
nsRestyleHint aRestyleHint,
|
||||
PRBool aFireAccessibilityEvents,
|
||||
RestyleTracker& aRestyleTracker);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include "mozFlushType.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include <stdio.h> // for FILE definition
|
||||
#include "nsRefreshDriver.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
@ -999,6 +1000,37 @@ public:
|
||||
PRUint64 GetPaintCount() { return mPaintCount; }
|
||||
void IncrementPaintCount() { ++mPaintCount; }
|
||||
|
||||
/**
|
||||
* Refresh observer management.
|
||||
*/
|
||||
protected:
|
||||
virtual PRBool AddRefreshObserverExternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType);
|
||||
PRBool AddRefreshObserverInternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType);
|
||||
virtual PRBool RemoveRefreshObserverExternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType);
|
||||
PRBool RemoveRefreshObserverInternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType);
|
||||
public:
|
||||
PRBool AddRefreshObserver(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType) {
|
||||
#ifdef _IMPL_NS_LAYOUT
|
||||
return AddRefreshObserverInternal(aObserver, aFlushType);
|
||||
#else
|
||||
return AddRefreshObserverExternal(aObserver, aFlushType);
|
||||
#endif
|
||||
}
|
||||
|
||||
PRBool RemoveRefreshObserver(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType) {
|
||||
#ifdef _IMPL_NS_LAYOUT
|
||||
return RemoveRefreshObserverInternal(aObserver, aFlushType);
|
||||
#else
|
||||
return RemoveRefreshObserverExternal(aObserver, aFlushType);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize and shut down static variables.
|
||||
*/
|
||||
|
@ -3441,6 +3441,14 @@ nsLayoutUtils::SurfaceFromElement(nsIDOMElement *aElement,
|
||||
if (node && ve) {
|
||||
nsHTMLVideoElement *video = static_cast<nsHTMLVideoElement*>(ve.get());
|
||||
|
||||
unsigned short readyState;
|
||||
if (NS_SUCCEEDED(ve->GetReadyState(&readyState)) &&
|
||||
(readyState == nsIDOMHTMLMediaElement::HAVE_NOTHING ||
|
||||
readyState == nsIDOMHTMLMediaElement::HAVE_METADATA)) {
|
||||
result.mIsStillLoading = PR_TRUE;
|
||||
return result;
|
||||
}
|
||||
|
||||
// If it doesn't have a principal, just bail
|
||||
nsCOMPtr<nsIPrincipal> principal = video->GetCurrentPrincipal();
|
||||
if (!principal)
|
||||
@ -3492,8 +3500,13 @@ nsLayoutUtils::SurfaceFromElement(nsIDOMElement *aElement,
|
||||
|
||||
PRUint32 status;
|
||||
imgRequest->GetImageStatus(&status);
|
||||
if ((status & imgIRequest::STATUS_LOAD_COMPLETE) == 0)
|
||||
if ((status & imgIRequest::STATUS_LOAD_COMPLETE) == 0) {
|
||||
// Spec says to use GetComplete, but that only works on
|
||||
// nsIDOMHTMLImageElement, and we support all sorts of other stuff
|
||||
// here. Do this for now pending spec clarification.
|
||||
result.mIsStillLoading = (status & imgIRequest::STATUS_ERROR) == 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
// In case of data: URIs, we want to ignore principals;
|
||||
// they should have the originating content's principal,
|
||||
|
@ -1144,6 +1144,8 @@ public:
|
||||
};
|
||||
|
||||
struct SurfaceFromElementResult {
|
||||
SurfaceFromElementResult() : mIsStillLoading(PR_FALSE) {}
|
||||
|
||||
/* mSurface will contain the resulting surface, or will be NULL on error */
|
||||
nsRefPtr<gfxASurface> mSurface;
|
||||
/* The size of the surface */
|
||||
@ -1152,6 +1154,9 @@ public:
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
/* Whether the element was "write only", that is, the bits should not be exposed to content */
|
||||
PRBool mIsWriteOnly;
|
||||
/* Whether the element was still loading. Some consumers need to handle
|
||||
this case specially. */
|
||||
PRBool mIsStillLoading;
|
||||
};
|
||||
|
||||
static SurfaceFromElementResult SurfaceFromElement(nsIDOMElement *aElement,
|
||||
|
@ -3626,13 +3626,18 @@ PresShell::RecreateFramesFor(nsIContent* aContent)
|
||||
void
|
||||
nsIPresShell::PostRecreateFramesFor(Element* aElement)
|
||||
{
|
||||
FrameConstructor()->PostRestyleEvent(aElement, eRestyle_Self,
|
||||
FrameConstructor()->PostRestyleEvent(aElement, nsRestyleHint(0),
|
||||
nsChangeHint_ReconstructFrame);
|
||||
}
|
||||
|
||||
void
|
||||
nsIPresShell::RestyleForAnimation(Element* aElement)
|
||||
{
|
||||
// eRestyle_Self is ok here because animations are always tied to a
|
||||
// particular element and don't directly affect its kids. The kids
|
||||
// might have animations of their own, or inherit from aElement, but
|
||||
// we handle all that during restyling; we don't need to _force_
|
||||
// animation rule matching on the kids here.
|
||||
FrameConstructor()->PostAnimationRestyleEvent(aElement, eRestyle_Self,
|
||||
NS_STYLE_HINT_NONE);
|
||||
}
|
||||
@ -4902,7 +4907,7 @@ PresShell::DocumentStatesChanged(nsIDocument* aDocument,
|
||||
mDocument->GetRootElement(),
|
||||
aStateMask)) {
|
||||
mFrameConstructor->PostRestyleEvent(mDocument->GetRootElement(),
|
||||
eRestyle_Self, NS_STYLE_HINT_NONE);
|
||||
eRestyle_Subtree, NS_STYLE_HINT_NONE);
|
||||
VERIFY_STYLE_TREE;
|
||||
}
|
||||
}
|
||||
@ -5079,7 +5084,7 @@ nsIPresShell::ReconstructStyleDataInternal()
|
||||
return;
|
||||
}
|
||||
|
||||
mFrameConstructor->PostRestyleEvent(root, eRestyle_Self, NS_STYLE_HINT_NONE);
|
||||
mFrameConstructor->PostRestyleEvent(root, eRestyle_Subtree, NS_STYLE_HINT_NONE);
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
InvalidateAccessibleSubtree(nsnull);
|
||||
@ -7744,6 +7749,36 @@ PresShell::Observe(nsISupports* aSubject,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsIPresShell::AddRefreshObserverInternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType)
|
||||
{
|
||||
return GetPresContext()->RefreshDriver()->
|
||||
AddRefreshObserver(aObserver, aFlushType);
|
||||
}
|
||||
|
||||
/* virtual */ PRBool
|
||||
nsIPresShell::AddRefreshObserverExternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType)
|
||||
{
|
||||
return AddRefreshObserverInternal(aObserver, aFlushType);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsIPresShell::RemoveRefreshObserverInternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType)
|
||||
{
|
||||
return GetPresContext()->RefreshDriver()->
|
||||
RemoveRefreshObserver(aObserver, aFlushType);
|
||||
}
|
||||
|
||||
/* virtual */ PRBool
|
||||
nsIPresShell::RemoveRefreshObserverExternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType)
|
||||
{
|
||||
return RemoveRefreshObserverInternal(aObserver, aFlushType);
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// End of protected and private methods on the PresShell
|
||||
//------------------------------------------------------
|
||||
|
@ -276,7 +276,7 @@ nsMathMLTokenFrame::ProcessTextData()
|
||||
|
||||
// explicitly request a re-resolve to pick up the change of style
|
||||
PresContext()->PresShell()->FrameConstructor()->
|
||||
PostRestyleEvent(mContent->AsElement(), eRestyle_Self, NS_STYLE_HINT_NONE);
|
||||
PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree, NS_STYLE_HINT_NONE);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -525,7 +525,7 @@ nsMathMLmtableOuterFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
||||
|
||||
// Explicitly request a re-resolve and reflow in our subtree to pick up any changes
|
||||
presContext->PresShell()->FrameConstructor()->
|
||||
PostRestyleEvent(mContent->AsElement(), eRestyle_Self,
|
||||
PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree,
|
||||
nsChangeHint_ReflowFrame);
|
||||
|
||||
return NS_OK;
|
||||
@ -705,7 +705,7 @@ nsMathMLmtableFrame::RestyleTable()
|
||||
|
||||
// Explicitly request a re-resolve and reflow in our subtree to pick up any changes
|
||||
PresContext()->PresShell()->FrameConstructor()->
|
||||
PostRestyleEvent(mContent->AsElement(), eRestyle_Self,
|
||||
PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree,
|
||||
nsChangeHint_ReflowFrame);
|
||||
}
|
||||
|
||||
@ -766,7 +766,7 @@ nsMathMLmtrFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
||||
|
||||
// Explicitly request a re-resolve and reflow in our subtree to pick up any changes
|
||||
presContext->PresShell()->FrameConstructor()->
|
||||
PostRestyleEvent(mContent->AsElement(), eRestyle_Self,
|
||||
PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree,
|
||||
nsChangeHint_ReflowFrame);
|
||||
|
||||
return NS_OK;
|
||||
|
6
layout/reftests/bugs/569006-1-ref.html
Normal file
6
layout/reftests/bugs/569006-1-ref.html
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
This text should be visible
|
||||
</body>
|
||||
</html>
|
10
layout/reftests/bugs/569006-1.html
Normal file
10
layout/reftests/bugs/569006-1.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body::before { content: inherit; }
|
||||
</style>
|
||||
</head>
|
||||
<body onload="document.body.style.content = '"This text should be visible"';">
|
||||
</body>
|
||||
</html>
|
6
layout/reftests/bugs/571347-1-ref.html
Normal file
6
layout/reftests/bugs/571347-1-ref.html
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<head>
|
||||
<body style="color: green">
|
||||
This should be green
|
||||
</body>
|
||||
</head>
|
10
layout/reftests/bugs/571347-1a.html
Normal file
10
layout/reftests/bugs/571347-1a.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<head>
|
||||
<style>
|
||||
body { color: red; }
|
||||
.Foo { color: green; }
|
||||
</style>
|
||||
<body onload="document.body.className = 'abc Foo'" class="abc">
|
||||
This should be green
|
||||
</body>
|
||||
</head>
|
10
layout/reftests/bugs/571347-1b.html
Normal file
10
layout/reftests/bugs/571347-1b.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<head>
|
||||
<style>
|
||||
body { color: green; }
|
||||
.Foo { color: red; }
|
||||
</style>
|
||||
<body onload="document.body.className = 'abc foo'" class="Foo">
|
||||
This should be green
|
||||
</body>
|
||||
</head>
|
6
layout/reftests/bugs/571347-2-ref.html
Normal file
6
layout/reftests/bugs/571347-2-ref.html
Normal file
@ -0,0 +1,6 @@
|
||||
<!-- Quirks on purpose -->
|
||||
<head>
|
||||
<body style="color: green">
|
||||
This should be green
|
||||
</body>
|
||||
</head>
|
10
layout/reftests/bugs/571347-2a.html
Normal file
10
layout/reftests/bugs/571347-2a.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!-- Quirks on purpose -->
|
||||
<head>
|
||||
<style>
|
||||
body { color: red; }
|
||||
.Foo { color: green; }
|
||||
</style>
|
||||
<body onload="document.body.className = 'abc Foo'" class="abc">
|
||||
This should be green
|
||||
</body>
|
||||
</head>
|
10
layout/reftests/bugs/571347-2b.html
Normal file
10
layout/reftests/bugs/571347-2b.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!-- Quirks on purpose -->
|
||||
<head>
|
||||
<style>
|
||||
body { color: green; }
|
||||
.Foo { color: red; }
|
||||
</style>
|
||||
<body onload="document.body.className = 'abc bar'" class="Foo">
|
||||
This should be green
|
||||
</body>
|
||||
</head>
|
10
layout/reftests/bugs/571347-2c.html
Normal file
10
layout/reftests/bugs/571347-2c.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!-- Quirks on purpose -->
|
||||
<head>
|
||||
<style>
|
||||
body { color: red; }
|
||||
.Foo { color: green; }
|
||||
</style>
|
||||
<body onload="document.body.className = 'abc foO'" class="abc">
|
||||
This should be green
|
||||
</body>
|
||||
</head>
|
10
layout/reftests/bugs/571347-2d.html
Normal file
10
layout/reftests/bugs/571347-2d.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!-- Quirks on purpose -->
|
||||
<head>
|
||||
<style>
|
||||
body { color: green; }
|
||||
.Foo { color: red; }
|
||||
</style>
|
||||
<body onload="document.body.className = 'abc bar'" class="fOo">
|
||||
This should be green
|
||||
</body>
|
||||
</head>
|
@ -1444,6 +1444,13 @@ random-if(!haveTestPlugin) == 546071-1.html 546071-1-ref.html
|
||||
== 564054-1.html 564054-1-ref.html
|
||||
== 565819-1.html 565819-ref.html
|
||||
== 565819-2.html 565819-ref.html
|
||||
== 569006-1.html 569006-1-ref.html
|
||||
== 571281-1a.html 571281-1-ref.html
|
||||
== 571281-1b.html 571281-1-ref.html
|
||||
== 571281-1c.html 571281-1-ref.html
|
||||
== 571347-1a.html 571347-1-ref.html
|
||||
== 571347-1b.html 571347-1-ref.html
|
||||
== 571347-2a.html 571347-2-ref.html
|
||||
== 571347-2b.html 571347-2-ref.html
|
||||
== 571347-2c.html 571347-2-ref.html
|
||||
== 571347-2d.html 571347-2-ref.html
|
||||
|
@ -147,6 +147,9 @@ FORCE_STATIC_LIB = 1
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(srcdir)/../base \
|
||||
-I$(srcdir)/../generic \
|
||||
-I$(srcdir)/../xul/base/src \
|
||||
-I$(srcdir)/../../content/base/src \
|
||||
-I$(srcdir)/../../content/html/content/src \
|
||||
-I$(srcdir)/../../content/xbl/src \
|
||||
|
@ -706,6 +706,67 @@ static const PLDHashTableOps AttributeSelectorOps = {
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------
|
||||
|
||||
// Class selectors hash table.
|
||||
struct ClassSelectorEntry : public PLDHashEntryHdr {
|
||||
nsIAtom *mClass;
|
||||
nsTArray<nsCSSSelector*> mSelectors;
|
||||
};
|
||||
|
||||
static void
|
||||
ClassSelector_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
|
||||
{
|
||||
(static_cast<ClassSelectorEntry*>(hdr))->~ClassSelectorEntry();
|
||||
}
|
||||
|
||||
static PRBool
|
||||
ClassSelector_InitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
||||
const void *key)
|
||||
{
|
||||
ClassSelectorEntry *entry = static_cast<ClassSelectorEntry*>(hdr);
|
||||
new (entry) ClassSelectorEntry();
|
||||
entry->mClass = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
static nsIAtom*
|
||||
ClassSelector_GetKey(PLDHashTable *table, const PLDHashEntryHdr *hdr)
|
||||
{
|
||||
const ClassSelectorEntry *entry = static_cast<const ClassSelectorEntry*>(hdr);
|
||||
return entry->mClass;
|
||||
}
|
||||
|
||||
// Case-sensitive ops.
|
||||
static const RuleHashTableOps ClassSelector_CSOps = {
|
||||
{
|
||||
PL_DHashAllocTable,
|
||||
PL_DHashFreeTable,
|
||||
PL_DHashVoidPtrKeyStub,
|
||||
RuleHash_CSMatchEntry,
|
||||
PL_DHashMoveEntryStub,
|
||||
ClassSelector_ClearEntry,
|
||||
PL_DHashFinalizeStub,
|
||||
ClassSelector_InitEntry
|
||||
},
|
||||
ClassSelector_GetKey
|
||||
};
|
||||
|
||||
// Case-insensitive ops.
|
||||
static const RuleHashTableOps ClassSelector_CIOps = {
|
||||
{
|
||||
PL_DHashAllocTable,
|
||||
PL_DHashFreeTable,
|
||||
RuleHash_CIHashKey,
|
||||
RuleHash_CIMatchEntry,
|
||||
PL_DHashMoveEntryStub,
|
||||
ClassSelector_ClearEntry,
|
||||
PL_DHashFinalizeStub,
|
||||
ClassSelector_InitEntry
|
||||
},
|
||||
ClassSelector_GetKey
|
||||
};
|
||||
|
||||
//--------------------------------
|
||||
|
||||
struct RuleCascadeData {
|
||||
@ -721,6 +782,10 @@ struct RuleCascadeData {
|
||||
sizeof(AttributeSelectorEntry), 16);
|
||||
PL_DHashTableInit(&mAnonBoxRules, &RuleHash_TagTable_Ops, nsnull,
|
||||
sizeof(RuleHashTagTableEntry), 16);
|
||||
PL_DHashTableInit(&mClassSelectors,
|
||||
aQuirksMode ? &ClassSelector_CIOps.ops :
|
||||
&ClassSelector_CSOps.ops,
|
||||
nsnull, sizeof(ClassSelectorEntry), 16);
|
||||
memset(mPseudoElementRuleHashes, 0, sizeof(mPseudoElementRuleHashes));
|
||||
#ifdef MOZ_XUL
|
||||
PL_DHashTableInit(&mXULTreeRules, &RuleHash_TagTable_Ops, nsnull,
|
||||
@ -732,7 +797,10 @@ struct RuleCascadeData {
|
||||
{
|
||||
PL_DHashTableFinish(&mAttributeSelectors);
|
||||
PL_DHashTableFinish(&mAnonBoxRules);
|
||||
PL_DHashTableFinish(&mClassSelectors);
|
||||
#ifdef MOZ_XUL
|
||||
PL_DHashTableFinish(&mXULTreeRules);
|
||||
#endif
|
||||
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(mPseudoElementRuleHashes); ++i) {
|
||||
delete mPseudoElementRuleHashes[i];
|
||||
}
|
||||
@ -742,7 +810,7 @@ struct RuleCascadeData {
|
||||
mPseudoElementRuleHashes[nsCSSPseudoElements::ePseudo_PseudoElementCount];
|
||||
nsTArray<nsCSSSelector*> mStateSelectors;
|
||||
PRUint32 mSelectorDocumentStates;
|
||||
nsTArray<nsCSSSelector*> mClassSelectors;
|
||||
PLDHashTable mClassSelectors;
|
||||
nsTArray<nsCSSSelector*> mIDSelectors;
|
||||
PLDHashTable mAttributeSelectors;
|
||||
PLDHashTable mAnonBoxRules;
|
||||
@ -2329,10 +2397,17 @@ nsCSSRuleProcessor::RulesMatching(XULTreeRuleProcessorData* aData)
|
||||
}
|
||||
#endif
|
||||
|
||||
inline PRBool
|
||||
IsSiblingOperator(PRUnichar oper)
|
||||
static inline nsRestyleHint RestyleHintForOp(PRUnichar oper)
|
||||
{
|
||||
return oper == PRUnichar('+') || oper == PRUnichar('~');
|
||||
if (oper == PRUnichar('+') || oper == PRUnichar('~')) {
|
||||
return eRestyle_LaterSiblings;
|
||||
}
|
||||
|
||||
if (oper != PRUnichar(0)) {
|
||||
return eRestyle_Subtree;
|
||||
}
|
||||
|
||||
return eRestyle_Self;
|
||||
}
|
||||
|
||||
nsRestyleHint
|
||||
@ -2355,8 +2430,7 @@ nsCSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData)
|
||||
for(; iter != end; ++iter) {
|
||||
nsCSSSelector* selector = *iter;
|
||||
|
||||
nsRestyleHint possibleChange = IsSiblingOperator(selector->mOperator) ?
|
||||
eRestyle_LaterSiblings : eRestyle_Self;
|
||||
nsRestyleHint possibleChange = RestyleHintForOp(selector->mOperator);
|
||||
|
||||
// If hint already includes all the bits of possibleChange,
|
||||
// don't bother calling SelectorMatches, since even if it returns false
|
||||
@ -2397,8 +2471,7 @@ AttributeEnumFunc(nsCSSSelector* aSelector, AttributeEnumData* aData)
|
||||
{
|
||||
AttributeRuleProcessorData *data = aData->data;
|
||||
|
||||
nsRestyleHint possibleChange = IsSiblingOperator(aSelector->mOperator) ?
|
||||
eRestyle_LaterSiblings : eRestyle_Self;
|
||||
nsRestyleHint possibleChange = RestyleHintForOp(aSelector->mOperator);
|
||||
|
||||
// If enumData->change already includes all the bits of possibleChange, don't
|
||||
// bother calling SelectorMatches, since even if it returns false
|
||||
@ -2430,7 +2503,7 @@ nsCSSRuleProcessor::HasAttributeDependentStyle(AttributeRuleProcessorData* aData
|
||||
aData->mNameSpaceID == kNameSpaceID_XUL &&
|
||||
aData->mElement == aData->mElement->GetOwnerDoc()->GetRootElement())
|
||||
{
|
||||
data.change = nsRestyleHint(data.change | eRestyle_Self);
|
||||
data.change = nsRestyleHint(data.change | eRestyle_Subtree);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2452,10 +2525,23 @@ nsCSSRuleProcessor::HasAttributeDependentStyle(AttributeRuleProcessorData* aData
|
||||
}
|
||||
|
||||
if (aData->mAttribute == aData->mElement->GetClassAttributeName()) {
|
||||
nsCSSSelector **iter = cascade->mClassSelectors.Elements(),
|
||||
**end = iter + cascade->mClassSelectors.Length();
|
||||
for(; iter != end; ++iter) {
|
||||
AttributeEnumFunc(*iter, &data);
|
||||
const nsAttrValue* elementClasses = aData->mClasses;
|
||||
if (elementClasses) {
|
||||
PRInt32 atomCount = elementClasses->GetAtomCount();
|
||||
for (PRInt32 i = 0; i < atomCount; ++i) {
|
||||
nsIAtom* curClass = elementClasses->AtomAt(i);
|
||||
ClassSelectorEntry *entry =
|
||||
static_cast<ClassSelectorEntry*>
|
||||
(PL_DHashTableOperate(&cascade->mClassSelectors,
|
||||
curClass, PL_DHASH_LOOKUP));
|
||||
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
|
||||
nsCSSSelector **iter = entry->mSelectors.Elements(),
|
||||
**end = iter + entry->mSelectors.Length();
|
||||
for(; iter != end; ++iter) {
|
||||
AttributeEnumFunc(*iter, &data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2580,8 +2666,15 @@ AddSelector(RuleCascadeData* aCascade,
|
||||
}
|
||||
|
||||
// Build mClassSelectors
|
||||
if (aSelectorPart->mClassList) {
|
||||
aCascade->mClassSelectors.AppendElement(aSelectorInTopLevel);
|
||||
for (nsAtomList* curClass = aSelectorPart->mClassList; curClass;
|
||||
curClass = curClass->mNext) {
|
||||
ClassSelectorEntry *entry =
|
||||
static_cast<ClassSelectorEntry*>(PL_DHashTableOperate(&aCascade->mClassSelectors,
|
||||
curClass->mAtom,
|
||||
PL_DHASH_ADD));
|
||||
if (entry) {
|
||||
entry->mSelectors.AppendElement(aSelectorInTopLevel);
|
||||
}
|
||||
}
|
||||
|
||||
// Build mAttributeSelectors.
|
||||
|
@ -71,6 +71,7 @@
|
||||
#include "nsContentErrors.h"
|
||||
#include "nsRuleProcessorData.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
@ -455,52 +456,46 @@ nsHTMLStyleSheet::Reset(nsIURI* aURL)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLStyleSheet::SetLinkColor(nscolor aColor)
|
||||
nsHTMLStyleSheet::ImplLinkColorSetter(nsRefPtr<HTMLColorRule>& aRule, nscolor aColor)
|
||||
{
|
||||
if (mLinkRule) {
|
||||
if (mLinkRule->mColor == aColor)
|
||||
if (aRule && aRule->mColor == aColor) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mLinkRule = new HTMLColorRule();
|
||||
if (!mLinkRule)
|
||||
aRule = new HTMLColorRule();
|
||||
if (!aRule)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mLinkRule->mColor = aColor;
|
||||
aRule->mColor = aColor;
|
||||
// Now make sure we restyle any links that might need it. This
|
||||
// shouldn't happen often, so just rebuilding everything is ok.
|
||||
if (mDocument && mDocument->GetPrimaryShell()) {
|
||||
Element* root = mDocument->GetRootElement();
|
||||
if (root) {
|
||||
mDocument->GetPrimaryShell()->FrameConstructor()->
|
||||
PostRestyleEvent(root, eRestyle_Subtree, NS_STYLE_HINT_NONE);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLStyleSheet::SetLinkColor(nscolor aColor)
|
||||
{
|
||||
return ImplLinkColorSetter(mLinkRule, aColor);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsHTMLStyleSheet::SetActiveLinkColor(nscolor aColor)
|
||||
{
|
||||
if (mActiveRule) {
|
||||
if (mActiveRule->mColor == aColor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mActiveRule = new HTMLColorRule();
|
||||
if (!mActiveRule)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mActiveRule->mColor = aColor;
|
||||
return NS_OK;
|
||||
return ImplLinkColorSetter(mActiveRule, aColor);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLStyleSheet::SetVisitedLinkColor(nscolor aColor)
|
||||
{
|
||||
if (mVisitedRule) {
|
||||
if (mVisitedRule->mColor == aColor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mVisitedRule = new HTMLColorRule();
|
||||
if (!mVisitedRule)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mVisitedRule->mColor = aColor;
|
||||
return NS_OK;
|
||||
return ImplLinkColorSetter(mVisitedRule, aColor);
|
||||
}
|
||||
|
||||
already_AddRefed<nsMappedAttributes>
|
||||
|
@ -127,6 +127,8 @@ private:
|
||||
nscolor mColor;
|
||||
};
|
||||
|
||||
// Implementation of SetLink/VisitedLink/ActiveLinkColor
|
||||
nsresult ImplLinkColorSetter(nsRefPtr<HTMLColorRule>& aRule, nscolor aColor);
|
||||
|
||||
class GenericTableRule;
|
||||
friend class GenericTableRule;
|
||||
|
@ -2124,6 +2124,18 @@ nsStyleContent::nsStyleContent(const nsStyleContent& aSource)
|
||||
|
||||
nsChangeHint nsStyleContent::CalcDifference(const nsStyleContent& aOther) const
|
||||
{
|
||||
// In ReResolveStyleContext we assume that if there's no existing
|
||||
// ::before or ::after and we don't have to restyle children of the
|
||||
// node then we can't end up with a ::before or ::after due to the
|
||||
// restyle of the node itself. That's not quite true, but the only
|
||||
// exception to the above is when the 'content' property of the node
|
||||
// changes and the pseudo-element inherits the changed value. Since
|
||||
// the code here triggers a frame change on the node in that case,
|
||||
// the optimization in ReResolveStyleContext is ok. But if we ever
|
||||
// change this code to not reconstruct frames on changes to the
|
||||
// 'content' property, then we will need to revisit the optimization
|
||||
// in ReResolveStyleContext.
|
||||
|
||||
if (mContentCount != aOther.mContentCount ||
|
||||
mIncrementCount != aOther.mIncrementCount ||
|
||||
mResetCount != aOther.mResetCount) {
|
||||
|
@ -1019,6 +1019,7 @@ function DocumentLoaded()
|
||||
if (gURLs[0].type == TYPE_LOAD) {
|
||||
++gTestResults.LoadOnly;
|
||||
dump("REFTEST TEST-PASS | " + gURLs[0].prettyPath + " | (LOAD ONLY)\n");
|
||||
gCurrentCanvas = null;
|
||||
FinishTestItem();
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user