Merge m-c to s-c

This commit is contained in:
Gregory Szorc 2011-12-14 20:49:23 -08:00
commit ba6209b00e
26 changed files with 480 additions and 70 deletions

View File

@ -1601,6 +1601,20 @@ public:
virtual void PostVisibilityUpdateEvent() = 0;
void SetNeedLayoutFlush() {
mNeedLayoutFlush = true;
if (mDisplayDocument) {
mDisplayDocument->SetNeedLayoutFlush();
}
}
void SetNeedStyleFlush() {
mNeedStyleFlush = true;
if (mDisplayDocument) {
mDisplayDocument->SetNeedStyleFlush();
}
}
private:
PRUint64 mWarnedAbout;
@ -1765,6 +1779,12 @@ protected:
// True if this document has links whose state needs updating
bool mHasLinksToUpdate;
// True if a layout flush might not be a no-op
bool mNeedLayoutFlush;
// True if a style flush might not be a no-op
bool mNeedStyleFlush;
// The document's script global object, the object from which the
// document can get its script context and scope. This is the
// *inner* window object.

View File

@ -6226,7 +6226,15 @@ nsDocument::CreateEvent(const nsAString& aEventType, nsIDOMEvent** aReturn)
void
nsDocument::FlushPendingNotifications(mozFlushType aType)
{
if ((!IsHTML() || aType > Flush_ContentAndNotify) &&
// We need to flush the sink for non-HTML documents (because the XML
// parser still does insertion with deferred notifications). We
// also need to flush the sink if this is a layout-related flush, to
// make sure that layout is started as needed. But we can skip that
// part if we have no presshell or if it's already done an initial
// reflow.
if ((!IsHTML() ||
(aType > Flush_ContentAndNotify && mPresShell &&
!mPresShell->DidInitialReflow())) &&
(mParser || mWeakSink)) {
nsCOMPtr<nsIContentSink> sink;
if (mParser) {
@ -6267,9 +6275,28 @@ nsDocument::FlushPendingNotifications(mozFlushType aType)
mParentDocument->FlushPendingNotifications(parentType);
}
nsCOMPtr<nsIPresShell> shell = GetShell();
if (shell) {
shell->FlushPendingNotifications(aType);
// We can optimize away getting our presshell and calling
// FlushPendingNotifications on it if we don't need a flush of the sort we're
// looking at. The one exception is if mInFlush is true, because in that
// case we might have set mNeedStyleFlush and mNeedLayoutFlush to false
// already but the presshell hasn't actually done the corresponding work yet.
// So if mInFlush and reentering this code, we need to flush the presshell.
if (mNeedStyleFlush ||
(mNeedLayoutFlush && aType >= Flush_InterruptibleLayout) ||
aType >= Flush_Display ||
mInFlush) {
nsCOMPtr<nsIPresShell> shell = GetShell();
if (shell) {
mNeedStyleFlush = false;
mNeedLayoutFlush = mNeedLayoutFlush && (aType < Flush_InterruptibleLayout);
// mInFlush is a bitfield, so can't us AutoRestore here. But we
// need to keep track of multi-level reentry correctly, so need
// to restore the old mInFlush value.
bool oldInFlush = mInFlush;
mInFlush = true;
shell->FlushPendingNotifications(aType);
mInFlush = oldInFlush;
}
}
}
@ -6759,7 +6786,7 @@ nsDocument::CreateElem(const nsAString& aName, nsIAtom *aPrefix, PRInt32 aNamesp
bool
nsDocument::IsSafeToFlush() const
{
nsCOMPtr<nsIPresShell> shell = GetShell();
nsIPresShell* shell = GetShell();
if (!shell)
return true;

View File

@ -1187,6 +1187,10 @@ protected:
// Whether we are currently in full-screen mode, as per the DOM API.
bool mIsFullScreen:1;
// Whether we're currently under a FlushPendingNotifications call to
// our presshell. This is used to handle flush reentry correctly.
bool mInFlush:1;
PRUint8 mXMLDeclarationBits;
nsInterfaceHashtable<nsVoidPtrHashKey, nsPIBoxObject> *mBoxObjectTable;

View File

@ -537,6 +537,7 @@ _TEST_FILES2 = \
file_bug707142_baseline.json \
file_bug707142_bom.json \
file_bug707142_utf-16.json \
test_reentrant_flush.html \
$(NULL)
_CHROME_FILES = \

View File

@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=709256
-->
<head>
<title>Test for Bug 709256</title>
<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=709256">Mozilla Bug 709256</a>
<p id="display">
<iframe id="test"
style="width: 100px" src="data:text/html,<body style='width: 100%'>">
</iframe>
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 709256 **/
addLoadEvent(function() {
var ifr = $("test");
var bod = ifr.contentDocument.body;
is(bod.getBoundingClientRect().width, 100,
"Width of body should be 100px to start with");
var resizeHandlerRan = false;
function handleResize() {
resizeHandlerRan = true;
is(bod.getBoundingClientRect().width, 50,
"Width of body should now be 50px");
}
var win = ifr.contentWindow;
win.addEventListener("resize", handleResize, false);
SpecialPowers.setFullZoom(win, 2);
is(resizeHandlerRan, false,
"Resize handler should not have run yet for this test to be valid");
// Now flush out layout on the subdocument, to trigger the resize handler
is(bod.getBoundingClientRect().width, 50, "Width of body should still be 50px");
is(resizeHandlerRan, true, "Resize handler should have run");
win.removeEventListener("resize", handleResize, false);
});
</script>
</pre>
</body>
</html>

View File

@ -852,3 +852,9 @@ nsSMILAnimationController::GetRefreshDriver()
nsPresContext* context = shell->GetPresContext();
return context ? context->RefreshDriver() : nsnull;
}
void
nsSMILAnimationController::FlagDocumentNeedsFlush()
{
mDocument->SetNeedStyleFlush();
}

View File

@ -96,9 +96,13 @@ public:
// (A resample performs the same operations as a sample but doesn't advance
// the current time and doesn't check if the container is paused)
void Resample() { DoSample(false); }
void SetResampleNeeded()
{
if (!mRunningSample) {
if (!mResampleNeeded) {
FlagDocumentNeedsFlush();
}
mResampleNeeded = true;
}
}
@ -198,6 +202,8 @@ protected:
virtual nsresult AddChild(nsSMILTimeContainer& aChild);
virtual void RemoveChild(nsSMILTimeContainer& aChild);
void FlagDocumentNeedsFlush();
// Members
nsAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD

View File

@ -989,6 +989,9 @@ nsBindingManager::AddToAttachedQueue(nsXBLBinding* aBinding)
PostProcessAttachedQueueEvent();
}
// Make sure that flushes will flush out the new items as needed.
mDocument->SetNeedStyleFlush();
return NS_OK;
}

View File

@ -2224,8 +2224,10 @@ nsDOMClassInfo::RegisterExternalClasses()
/* number of interfaces due to the terminating null */ \
for (size_t i = 0; i < count - 1; ++i) { \
if (!interface_list[i]) { \
/* We are moving the element at index i+1 and successors, */ \
/* so we must move only count - (i+1) elements total. */ \
memmove(&interface_list[i], &interface_list[i+1], \
sizeof(nsIID*) * (count - i)); \
sizeof(nsIID*) * (count - (i+1))); \
/* Make sure to examine the new pointer we ended up with at this */ \
/* slot, since it may be null too */ \
--i; \

View File

@ -59,6 +59,7 @@ PEGroupRuleNestedAtRule=%1$S rule not allowed within @media or @-moz-document ru
PEMozDocRuleBadFunc=Expected url(), url-prefix(), or domain() in @-moz-document rule but found '%1$S'.
PEMozDocRuleNotURI=Expected URI in @-moz-document rule but found '%1$S'.
PEMozDocRuleNotString=Expected string in @-moz-document rule regexp() function but found '%1$S'.
PEMozDocRuleEOF=next URI in @-moz-document rule
PEAtNSPrefixEOF=namespace prefix in @namespace rule
PEAtNSURIEOF=namespace URI in @namespace rule
PEAtNSUnexpected=Unexpected token within @namespace: '%1$S'.

View File

@ -1490,36 +1490,18 @@ JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj)
#include <valgrind/callgrind.h>
/*
* Wrapper for callgrind macros to stop warnings coming from their expansions.
*/
#if (__GNUC__ >= 5) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
# define WRAP_CALLGRIND(call) \
JS_BEGIN_MACRO \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wunused-but-set-variable\"") \
call; \
_Pragma("GCC diagnostic pop") \
JS_END_MACRO
#else
# define WRAP_CALLGRIND(call) \
JS_BEGIN_MACRO \
call; \
JS_END_MACRO
#endif
JS_FRIEND_API(JSBool)
js_StartCallgrind()
{
WRAP_CALLGRIND(CALLGRIND_START_INSTRUMENTATION);
WRAP_CALLGRIND(CALLGRIND_ZERO_STATS);
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_START_INSTRUMENTATION);
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_ZERO_STATS);
return true;
}
JS_FRIEND_API(JSBool)
js_StopCallgrind()
{
WRAP_CALLGRIND(CALLGRIND_STOP_INSTRUMENTATION);
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_STOP_INSTRUMENTATION);
return true;
}
@ -1527,9 +1509,9 @@ JS_FRIEND_API(JSBool)
js_DumpCallgrind(const char *outfile)
{
if (outfile) {
WRAP_CALLGRIND(CALLGRIND_DUMP_STATS_AT(outfile));
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS_AT(outfile));
} else {
WRAP_CALLGRIND(CALLGRIND_DUMP_STATS);
JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS);
}
return true;

View File

@ -1010,7 +1010,7 @@ MarkWordConservatively(JSTracer *trc, jsuword w)
* original word. See bug 572678.
*/
#ifdef JS_VALGRIND
VALGRIND_MAKE_MEM_DEFINED(&w, sizeof(w));
JS_SILENCE_UNUSED_VALUE_IN_EXPR(VALGRIND_MAKE_MEM_DEFINED(&w, sizeof(w)));
#endif
MarkIfGCThingWord(trc, w);

View File

@ -440,4 +440,28 @@ typedef size_t jsbitmap;
#define JS_CLEAR_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] &= \
~((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1))))
/* Wrapper for various macros to stop warnings coming from their expansions. */
#if defined(__clang__)
# define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \
JS_BEGIN_MACRO \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wunused-value\"") \
expr; \
_Pragma("clang diagnostic pop") \
JS_END_MACRO
#elif (__GNUC__ >= 5) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
# define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \
JS_BEGIN_MACRO \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wunused-but-set-variable\"") \
expr; \
_Pragma("GCC diagnostic pop") \
JS_END_MACRO
#else
# define JS_SILENCE_UNUSED_VALUE_IN_EXPR(expr) \
JS_BEGIN_MACRO \
expr; \
JS_END_MACRO
#endif
#endif /* jsutil_h___ */

View File

@ -166,7 +166,7 @@ RestyleTracker::ProcessOneRestyle(Element* aElement,
}
void
RestyleTracker::ProcessRestyles()
RestyleTracker::DoProcessRestyles()
{
SAMPLE_LABEL("CSS", "ProcessRestyles");
// Make sure to not rebuild quote or counter lists while we're

View File

@ -94,7 +94,13 @@ public:
/**
* Process the restyles we've been tracking.
*/
void ProcessRestyles();
void ProcessRestyles() {
// Fast-path the common case (esp. for the animation restyle
// tracker) of not having anything to do.
if (mPendingRestyles.Count()) {
DoProcessRestyles();
}
}
// Return our ELEMENT_HAS_PENDING_(ANIMATION_)RESTYLE bit
PRUint32 RestyleBit() const {
@ -143,6 +149,11 @@ private:
nsRestyleHint aRestyleHint,
nsChangeHint aChangeHint);
/**
* The guts of our restyle processing.
*/
void DoProcessRestyles();
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

View File

@ -11703,6 +11703,11 @@ nsCSSFrameConstructor::PostRestyleEventInternal(bool aForLazyConstruction)
mObservingRefreshDriver = mPresShell->GetPresContext()->RefreshDriver()->
AddStyleFlushObserver(mPresShell);
}
// Unconditionally flag our document as needing a flush. The other
// option here would be a dedicated boolean to track whether we need
// to do so (set here and unset in ProcessPendingRestyles).
mPresShell->GetDocument()->SetNeedStyleFlush();
}
void

View File

@ -1774,11 +1774,13 @@ private:
void QuotesDirty() {
NS_PRECONDITION(mUpdateCount != 0, "Instant quote updates are bad news");
mQuotesDirty = true;
mDocument->SetNeedLayoutFlush();
}
void CountersDirty() {
NS_PRECONDITION(mUpdateCount != 0, "Instant counter updates are bad news");
mCountersDirty = true;
mDocument->SetNeedLayoutFlush();
}
public:

View File

@ -1677,6 +1677,7 @@ nsPresContext::PostMediaFeatureValuesChangedEvent()
NS_NewRunnableMethod(this, &nsPresContext::HandleMediaFeatureValuesChangedEvent);
if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
mPendingMediaFeatureValuesChanged = true;
mDocument->SetNeedStyleFlush();
}
}
}
@ -1886,6 +1887,7 @@ nsPresContext::RebuildUserFontSet()
}
mUserFontSetDirty = true;
mDocument->SetNeedStyleFlush();
// Somebody has already asked for the user font set, so we need to
// post an event to rebuild it. Setting the user font set to be dirty

View File

@ -2183,6 +2183,7 @@ PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight)
NS_NewRunnableMethod(this, &PresShell::FireResizeEvent);
if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent))) {
mResizeEvent = resizeEvent;
mDocument->SetNeedStyleFlush();
}
}
}
@ -2864,6 +2865,7 @@ PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
// we've hit a reflow root or the root frame
if (!wasDirty) {
mDirtyRoots.AppendElement(f);
mDocument->SetNeedLayoutFlush();
}
#ifdef DEBUG
else {
@ -3444,6 +3446,7 @@ PresShell::ScrollContentIntoView(nsIContent* aContent,
mContentToScrollToFlags = aFlags;
// Flush layout and attempt to scroll in the process.
currentDoc->SetNeedLayoutFlush();
currentDoc->FlushPendingNotifications(Flush_InterruptibleLayout);
// If mContentToScrollTo is non-null, that means we interrupted the reflow
@ -3835,7 +3838,7 @@ PresShell::UnsuppressPainting()
// the reflows and get all the frames where we want them
// before actually unlocking the painting. Otherwise
// go ahead and unlock now.
if (mDirtyRoots.Length() > 0)
if (!mDirtyRoots.IsEmpty())
mShouldUnsuppressPainting = true;
else
UnsuppressAndInvalidate();
@ -3966,6 +3969,12 @@ PresShell::IsSafeToFlush() const
void
PresShell::FlushPendingNotifications(mozFlushType aType)
{
/**
* VERY IMPORTANT: If you add some sort of new flushing to this
* method, make sure to add the relevant SetNeedLayoutFlush or
* SetNeedStyleFlush calls on the document.
*/
#ifdef NS_FUNCTION_TIMER
NS_TIME_FUNCTION_DECLARE_DOCURL;
static const char *flushTypeNames[] = {
@ -4100,6 +4109,11 @@ PresShell::FlushPendingNotifications(mozFlushType aType)
mContentToScrollToFlags);
mContentToScrollTo = nsnull;
}
} else if (!mIsDestroying && mSuppressInterruptibleReflows &&
aType == Flush_InterruptibleLayout) {
// We suppressed this flush, but the document thinks it doesn't
// need to flush anymore. Let it know what's really going on.
mDocument->SetNeedLayoutFlush();
}
if (aType >= Flush_Layout) {
@ -7343,6 +7357,7 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
mFramesToDirty.EnumerateEntries(&MarkFramesDirtyToRoot, target);
NS_ASSERTION(NS_SUBTREE_DIRTY(target), "Why is the target not dirty?");
mDirtyRoots.AppendElement(target);
mDocument->SetNeedLayoutFlush();
// Clear mFramesToDirty after we've done the NS_SUBTREE_DIRTY(target)
// assertion so that if it fails it's easier to see what's going on.
@ -7385,7 +7400,7 @@ PresShell::DoVerifyReflow()
ok ? "ok" : "failed");
}
if (0 != mDirtyRoots.Length()) {
if (!mDirtyRoots.IsEmpty()) {
printf("XXX yikes! reflow commands queued during verify-reflow\n");
}
}
@ -7395,10 +7410,15 @@ PresShell::DoVerifyReflow()
bool
PresShell::ProcessReflowCommands(bool aInterruptible)
{
if (mDirtyRoots.IsEmpty() && !mShouldUnsuppressPainting) {
// Nothing to do; bail out
return true;
}
NS_TIME_FUNCTION_WITH_DOCURL;
mozilla::TimeStamp timerStart = mozilla::TimeStamp::Now();
bool interrupted = false;
if (0 != mDirtyRoots.Length()) {
if (!mDirtyRoots.IsEmpty()) {
#ifdef DEBUG
if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) {
@ -7434,10 +7454,10 @@ PresShell::ProcessReflowCommands(bool aInterruptible)
// Keep going until we're out of reflow commands, or we've run
// past our deadline, or we're interrupted.
} while (!interrupted && mDirtyRoots.Length() &&
} while (!interrupted && !mDirtyRoots.IsEmpty() &&
(!aInterruptible || PR_IntervalNow() < deadline));
interrupted = mDirtyRoots.Length() != 0;
interrupted = !mDirtyRoots.IsEmpty();
}
// Exiting the scriptblocker might have killed us
@ -7460,13 +7480,16 @@ PresShell::ProcessReflowCommands(bool aInterruptible)
// after DidDoReflow(), since that method can change whether there are
// dirty roots around by flushing, and there's no point in posting a
// reflow event just to have the flush revoke it.
if (mDirtyRoots.Length())
if (!mDirtyRoots.IsEmpty()) {
MaybeScheduleReflow();
// And tell our document that we might need flushing
mDocument->SetNeedLayoutFlush();
}
}
}
if (!mIsDestroying && mShouldUnsuppressPainting &&
mDirtyRoots.Length() == 0) {
mDirtyRoots.IsEmpty()) {
// We only unlock if we're out of reflows. It's pointless
// to unlock if reflows are still pending, since reflows
// are just going to thrash the frames around some more. By

View File

@ -546,6 +546,9 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext,
// dispatch them the next time we get a refresh driver notification
// or the next time somebody calls
// nsPresShell::FlushPendingNotifications.
if (!mPendingEvents.IsEmpty()) {
mPresContext->Document()->SetNeedStyleFlush();
}
}
return GetAnimationRule(aElement, aStyleContext->GetPseudoType());
@ -901,7 +904,7 @@ nsAnimationManager::WillRefresh(mozilla::TimeStamp aTime)
}
void
nsAnimationManager::DispatchEvents()
nsAnimationManager::DoDispatchEvents()
{
EventArray events;
mPendingEvents.SwapElements(events);

View File

@ -131,7 +131,12 @@ public:
* accumulate animationstart events at other points when style
* contexts are created.
*/
void DispatchEvents();
void DispatchEvents() {
// Fast-path the common case: no events
if (!mPendingEvents.IsEmpty()) {
DoDispatchEvents();
}
}
private:
ElementAnimations* GetElementAnimations(mozilla::dom::Element *aElement,
@ -149,6 +154,9 @@ private:
nsCSSKeyframesRule* KeyframesRuleFor(const nsSubstring& aName);
// The guts of DispatchEvents
void DoDispatchEvents();
bool mKeyframesListIsDirty;
nsDataHashtable<nsStringHashKey, nsCSSKeyframesRule*> mKeyframesRules;

View File

@ -335,22 +335,23 @@ protected:
void PopGroup();
bool ParseRuleSet(RuleAppendFunc aAppendFunc, void* aProcessData,
bool aInsideBraces = false);
bool ParseAtRule(RuleAppendFunc aAppendFunc, void* aProcessData);
bool aInsideBraces = false);
bool ParseAtRule(RuleAppendFunc aAppendFunc, void* aProcessData,
bool aInAtRule);
bool ParseCharsetRule(RuleAppendFunc aAppendFunc, void* aProcessData);
bool ParseImportRule(RuleAppendFunc aAppendFunc, void* aProcessData);
bool ParseURLOrString(nsString& aURL);
bool GatherMedia(nsMediaList* aMedia,
bool aInAtRule);
bool aInAtRule);
bool ParseMediaQuery(bool aInAtRule, nsMediaQuery **aQuery,
bool *aHitStop);
bool *aHitStop);
bool ParseMediaQueryExpression(nsMediaQuery* aQuery);
void ProcessImport(const nsString& aURLSpec,
nsMediaList* aMedia,
RuleAppendFunc aAppendFunc,
void* aProcessData);
bool ParseGroupRule(css::GroupRule* aRule, RuleAppendFunc aAppendFunc,
void* aProcessData);
void* aProcessData);
bool ParseMediaRule(RuleAppendFunc aAppendFunc, void* aProcessData);
bool ParseMozDocumentRule(RuleAppendFunc aAppendFunc, void* aProcessData);
bool ParseNameSpaceRule(RuleAppendFunc aAppendFunc, void* aProcessData);
@ -361,7 +362,7 @@ protected:
bool ParseFontFaceRule(RuleAppendFunc aAppendFunc, void* aProcessData);
bool ParseFontDescriptor(nsCSSFontFaceRule* aRule);
bool ParseFontDescriptorValue(nsCSSFontDesc aDescID,
nsCSSValue& aValue);
nsCSSValue& aValue);
bool ParsePageRule(RuleAppendFunc aAppendFunc, void* aProcessData);
bool ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aProcessData);
@ -919,7 +920,7 @@ CSSParserImpl::ParseSheet(const nsAString& aInput,
continue; // legal here only
}
if (eCSSToken_AtKeyword == tk->mType) {
ParseAtRule(AppendRuleToSheet, this);
ParseAtRule(AppendRuleToSheet, this, false);
continue;
}
UngetToken();
@ -1050,7 +1051,7 @@ CSSParserImpl::ParseRule(const nsAString& aRule,
REPORT_UNEXPECTED(PEParseRuleWSOnly);
OUTPUT_ERROR();
} else if (eCSSToken_AtKeyword == tk->mType) {
ParseAtRule(AppendRuleToArray, &aResult);
ParseAtRule(AppendRuleToArray, &aResult, false);
}
else {
UngetToken();
@ -1508,14 +1509,10 @@ CSSParserImpl::SkipAtRule(bool aInsideBlock)
bool
CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc,
void* aData)
void* aData,
bool aInAtRule)
{
// If we ever allow nested at-rules, we need to be very careful about
// the error handling rules in the CSS spec. In particular, we need
// to pass in to ParseAtRule whether we're inside a block, we need to
// ensure that all the individual at-rule parsing functions terminate
// immediately when they hit a '}', and then we need to pass whether
// we're inside a block to SkipAtRule below.
nsCSSSection newSection;
bool (CSSParserImpl::*parseFunc)(RuleAppendFunc, void*);
@ -1560,16 +1557,27 @@ CSSParserImpl::ParseAtRule(RuleAppendFunc aAppendFunc,
OUTPUT_ERROR();
}
// Skip over unsupported at rule, don't advance section
return SkipAtRule(false);
return SkipAtRule(aInAtRule);
}
if (!(this->*parseFunc)(aAppendFunc, aData)) {
// Inside of @-rules, only the rules that can occur anywhere
// are allowed.
bool unnestable = aInAtRule && newSection != eCSSSection_General;
if (unnestable) {
REPORT_UNEXPECTED_TOKEN(PEGroupRuleNestedAtRule);
}
if (unnestable || !(this->*parseFunc)(aAppendFunc, aData)) {
// Skip over invalid at rule, don't advance section
OUTPUT_ERROR();
return SkipAtRule(false);
return SkipAtRule(aInAtRule);
}
mSection = newSection;
// Nested @-rules don't affect the top-level rule chain requirement
if (!aInAtRule) {
mSection = newSection;
}
return true;
}
@ -1637,7 +1645,7 @@ CSSParserImpl::ParseMediaQuery(bool aInAtRule,
}
if (eCSSToken_Symbol == mToken.mType && aInAtRule &&
(mToken.mSymbol == ';' || mToken.mSymbol == '{')) {
(mToken.mSymbol == ';' || mToken.mSymbol == '{' || mToken.mSymbol == '}' )) {
*aHitStop = true;
UngetToken();
return true;
@ -1701,7 +1709,7 @@ CSSParserImpl::ParseMediaQuery(bool aInAtRule,
}
if (eCSSToken_Symbol == mToken.mType && aInAtRule &&
(mToken.mSymbol == ';' || mToken.mSymbol == '{')) {
(mToken.mSymbol == ';' || mToken.mSymbol == '{' || mToken.mSymbol == '}')) {
*aHitStop = true;
UngetToken();
break;
@ -1742,14 +1750,14 @@ CSSParserImpl::GatherMedia(nsMediaList* aMedia,
}
if (aInAtRule) {
const PRUnichar stopChars[] =
{ PRUnichar(','), PRUnichar('{'), PRUnichar(';'), PRUnichar(0) };
{ PRUnichar(','), PRUnichar('{'), PRUnichar(';'), PRUnichar('}'), PRUnichar(0) };
SkipUntilOneOf(stopChars);
} else {
SkipUntil(',');
}
// Rely on SkipUntilOneOf leaving mToken around as the last token read.
if (mToken.mType == eCSSToken_Symbol && aInAtRule &&
(mToken.mSymbol == '{' || mToken.mSymbol == ';')) {
(mToken.mSymbol == '{' || mToken.mSymbol == ';' || mToken.mSymbol == '}')) {
UngetToken();
hitStop = true;
}
@ -1993,9 +2001,8 @@ CSSParserImpl::ParseGroupRule(css::GroupRule* aRule,
break;
}
if (eCSSToken_AtKeyword == mToken.mType) {
REPORT_UNEXPECTED_TOKEN(PEGroupRuleNestedAtRule);
OUTPUT_ERROR();
SkipAtRule(true); // group rules cannot contain @rules
// Parse for nested rules
ParseAtRule(aAppendFunc, aData, true);
continue;
}
UngetToken();
@ -2040,13 +2047,19 @@ CSSParserImpl::ParseMozDocumentRule(RuleAppendFunc aAppendFunc, void* aData)
css::DocumentRule::URL *urls = nsnull;
css::DocumentRule::URL **next = &urls;
do {
if (!GetToken(true) ||
!(eCSSToken_URL == mToken.mType ||
if (!GetToken(true)) {
REPORT_UNEXPECTED_EOF(PEMozDocRuleEOF);
delete urls;
return false;
}
if (!(eCSSToken_URL == mToken.mType ||
(eCSSToken_Function == mToken.mType &&
(mToken.mIdent.LowerCaseEqualsLiteral("url-prefix") ||
mToken.mIdent.LowerCaseEqualsLiteral("domain") ||
mToken.mIdent.LowerCaseEqualsLiteral("regexp"))))) {
REPORT_UNEXPECTED_TOKEN(PEMozDocRuleBadFunc);
UngetToken();
delete urls;
return false;
}

View File

@ -119,6 +119,7 @@ _TEST_FILES = test_acid3_test46.html \
test_bug470769.html \
test_bug499655.html \
test_bug499655.xhtml \
test_bug511909.html \
test_bug517224.html \
test_bug524175.html \
test_bug534804.html \

View File

@ -0,0 +1,205 @@
<html><!--
https://bugzilla.mozilla.org/show_bug.cgi?id=511909
--><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>@media and @-moz-document testcases</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
<style type="text/css">
a {
font-weight: bold;
}
#pink {
color: pink;
}
#green {
color: green;
}
#blue {
color: blue;
}
pre {
border: 1px solid black;
}
</style>
<style type="text/css">
@-moz-document regexp(".*test_bug511909.*"){
#d {
color: pink;
}
}
</style>
<style type="text/css">
@media screen {
#m {
color: green;
}
}
</style>
<style type="text/css">
@-moz-document regexp(".*test_bug511909.*"){
@media screen {
#dm {
color: blue;
}
}
}
</style>
<!-- should parse -->
<style type="text/css">
@media print {
@-moz-document regexp("not_this_url"),}
#mx {
color: pink;
}
}
}
</style>
<!-- should parse -->
<style type="text/css">
@-moz-document regexp("not_this_url"){
@media print ,}
#mxx {
color: blue;
}
}
}
</style>
<style type="text/css">
@media screen {
@-moz-document regexp(".*test_bug511909.*"){
#md {
color: green;
}
}
}
</style>
<style type="text/css">
@media screen {
@-moz-document regexp(".*test_bug511909.*"){
@media screen {
@-moz-document regexp(".*test_bug511909.*"){
@media screen {
#me {
color: blue;
}
}
}
}
}
}
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=511909">Mozilla Bug 511909</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var pink = getComputedStyle(document.getElementById("pink"), "");
var green = getComputedStyle(document.getElementById("green"), "");
var blue = getComputedStyle(document.getElementById("blue"), "");
var cs1 = getComputedStyle(document.getElementById("d"), "");
var cs2 = getComputedStyle(document.getElementById("m"), "");
var cs3 = getComputedStyle(document.getElementById("dm"), "");
var cs4 = getComputedStyle(document.getElementById("md"), "");
var cs5 = getComputedStyle(document.getElementById("mx"), "");
var cs6 = getComputedStyle(document.getElementById("mxx"), "");
var cs7 = getComputedStyle(document.getElementById("me"), "");
is(cs1.color, pink.color, "@-moz-document applies");
is(cs2.color, green.color, "@media applies");
is(cs3.color, blue.color, "@media nested in @-moz-document applies");
is(cs4.color, green.color, "@-moz-document nested in @media applies");
is(cs5.color, pink.color, "broken @media nested in @-moz-document correctly handled");
is(cs6.color, blue.color, "broken @-moz-document nested in @media correctly handled");
is(cs7.color, blue.color, "@media nested in @-moz-document nested in @media applies");
SimpleTest.finish();
});
</script>
<div>
<pre>default style
</pre>
<a id="pink">This line should be pink</a><br>
<a id="green">This line should be green</a><br>
<a id="blue">This line should be blue</a><br>
<pre>@-moz-document {...}
</pre>
<a id="d">This line should be pink</a><br>
<pre>@media screen {...}
</pre>
<a id="m">This line should be green</a><br>
<pre>@-moz-document {
@media screen {...}
}
</pre>
<a id="dm">This line should be blue</a><br>
<pre>@media print {
@-moz-document regexp("not_this_url"),}
#mx {
color: pink;
}
}
}
</pre>
<a id="mx">This line should be pink</a><br></div>
<pre>@-moz-document regexp("not_this_url"){
@media print ,}
#mxx {
color: blue;
}
}
}
</pre>
<a id="mxx">This line should be blue</a><br>
<pre>@media screen {
@-moz-documen {...}
}
</pre>
<a id="md">This line should be green</a><br>
<pre>@media screen {
@-moz-document {
@media screen {...}
}
}
</pre>
<a id="me">This line should be blue</a><br>
</body></html>

View File

@ -55,7 +55,7 @@ _BROWSER_FILES = \
remote_forms.js \
remote_formsZoom.js \
remote_vkb.js \
browser_addons.js \
$(warning browser_addons.js disabled due to failures - bug 710956) \
browser_addons_locales.js \
browser_appmenu.js \
browser_autocompletesearch.js \

View File

@ -281,6 +281,9 @@ NS_IMETHODIMP nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight
DoSetWindowDimensions(aWidth, aHeight);
} else {
mDelayedResize.SizeTo(aWidth, aHeight);
if (mPresShell && mPresShell->GetDocument()) {
mPresShell->GetDocument()->SetNeedStyleFlush();
}
}
}