зеркало из https://github.com/mozilla/pjs.git
Merge.
This commit is contained in:
Коммит
f86a783ddf
|
@ -85,7 +85,8 @@ nsIAtom *nsDocAccessible::gLastFocusedFrameType = nsnull;
|
|||
//-----------------------------------------------------
|
||||
nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell):
|
||||
nsHyperTextAccessibleWrap(aDOMNode, aShell), mWnd(nsnull),
|
||||
mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE), mIsLoadCompleteFired(PR_FALSE)
|
||||
mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE),
|
||||
mIsLoadCompleteFired(PR_FALSE), mInFlushPendingEvents(PR_FALSE)
|
||||
{
|
||||
// For GTK+ native window, we do nothing here.
|
||||
if (!mDOMNode)
|
||||
|
@ -589,7 +590,10 @@ NS_IMETHODIMP nsDocAccessible::Shutdown()
|
|||
mEventsToFire.Clear();
|
||||
// Make sure we release the kung fu death grip which is always
|
||||
// there when there are still events left to be fired
|
||||
NS_RELEASE_THIS();
|
||||
// If FlushPendingEvents() is in call stack,
|
||||
// kung fu death grip will be released there.
|
||||
if (!mInFlushPendingEvents)
|
||||
NS_RELEASE_THIS();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1505,6 +1509,7 @@ nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent)
|
|||
|
||||
NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
|
||||
{
|
||||
mInFlushPendingEvents = PR_TRUE;
|
||||
PRUint32 length = mEventsToFire.Count();
|
||||
NS_ASSERTION(length, "How did we get here without events to fire?");
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||
|
@ -1625,7 +1630,8 @@ NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
|
|||
#endif
|
||||
nsCOMPtr<nsIAccessibleCaretMoveEvent> caretMoveEvent =
|
||||
new nsAccCaretMoveEvent(accessible, caretOffset);
|
||||
NS_ENSURE_TRUE(caretMoveEvent, NS_ERROR_OUT_OF_MEMORY);
|
||||
if (!caretMoveEvent)
|
||||
break; // Out of memory, break out to release kung fu death grip
|
||||
|
||||
FireAccessibleEvent(caretMoveEvent);
|
||||
|
||||
|
@ -1661,6 +1667,7 @@ NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
|
|||
// After a flood of events, reset so that user input flag is off
|
||||
nsAccEvent::ResetLastInputState();
|
||||
|
||||
mInFlushPendingEvents = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -221,6 +221,7 @@ class nsDocAccessible : public nsHyperTextAccessibleWrap,
|
|||
protected:
|
||||
PRBool mIsAnchor;
|
||||
PRBool mIsAnchorJumped;
|
||||
PRBool mInFlushPendingEvents;
|
||||
static PRUint32 gLastFocusedAccessiblesState;
|
||||
static nsIAtom *gLastFocusedFrameType;
|
||||
};
|
||||
|
|
15
configure.in
15
configure.in
|
@ -4255,6 +4255,18 @@ MOZ_ARG_WITH_STRING(java-bin-path,
|
|||
[ --with-java-bin-path=dir Location of Java binaries (java, javac, jar)],
|
||||
JAVA_BIN_PATH=$withval)
|
||||
|
||||
dnl ========================================================
|
||||
dnl Use ARM userspace kernel helpers; tell NSPR to enable
|
||||
dnl their usage and use them in spidermonkey.
|
||||
dnl ========================================================
|
||||
MOZ_ARG_WITH_BOOL(arm-kuser,
|
||||
[ --with-arm-kuser Use kuser helpers (Linux/ARM only -- requires kernel 2.6.13 or later)],
|
||||
USE_ARM_KUSER=1,
|
||||
USE_ARM_KUSER=)
|
||||
if test -n "$USE_ARM_KUSER"; then
|
||||
AC_DEFINE(USE_ARM_KUSER)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl =
|
||||
dnl = Application
|
||||
|
@ -8264,6 +8276,9 @@ if test -z "$MOZ_NATIVE_NSPR" || test "$MOZ_LDAP_XPCOM"; then
|
|||
if test -n "$HAVE_64BIT_OS"; then
|
||||
ac_configure_args="$ac_configure_args --enable-64bit"
|
||||
fi
|
||||
if test -n "$USE_ARM_KUSER"; then
|
||||
ac_configure_args="$ac_configure_args --with-arm-kuser"
|
||||
fi
|
||||
AC_OUTPUT_SUBDIRS(nsprpub)
|
||||
ac_configure_args="$_SUBDIR_CONFIG_ARGS"
|
||||
fi
|
||||
|
|
|
@ -397,6 +397,7 @@ GK_ATOM(i, "i")
|
|||
GK_ATOM(id, "id")
|
||||
GK_ATOM(_if, "if")
|
||||
GK_ATOM(iframe, "iframe")
|
||||
GK_ATOM(ignore, "ignore")
|
||||
GK_ATOM(ignorecase, "ignorecase")
|
||||
GK_ATOM(ignorekeys, "ignorekeys")
|
||||
GK_ATOM(ilayer, "ilayer")
|
||||
|
@ -802,6 +803,7 @@ GK_ATOM(staticHint, "staticHint")
|
|||
GK_ATOM(statustext, "statustext")
|
||||
GK_ATOM(stop, "stop")
|
||||
GK_ATOM(stretch, "stretch")
|
||||
GK_ATOM(stretch_to_fit, "stretch-to-fit")
|
||||
GK_ATOM(strike, "strike")
|
||||
GK_ATOM(string, "string")
|
||||
GK_ATOM(stringLength, "string-length")
|
||||
|
|
|
@ -3877,19 +3877,21 @@ nsHTMLDocument::GetDocumentAllResult(const nsAString& aID, nsISupports** aResult
|
|||
NS_ENSURE_TRUE(entry->mDocAllList, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
nsRefPtr<nsContentList> docAllList = entry->mDocAllList;
|
||||
|
||||
// Check if there are more than 1 entries. Do this by getting the second one
|
||||
// rather than the length since getting the length always requires walking
|
||||
// the entire document.
|
||||
|
||||
nsIContent* cont = entry->mDocAllList->Item(1, PR_TRUE);
|
||||
nsIContent* cont = docAllList->Item(1, PR_TRUE);
|
||||
if (cont) {
|
||||
NS_ADDREF(*aResult = static_cast<nsIDOMNodeList*>(entry->mDocAllList));
|
||||
NS_ADDREF(*aResult = static_cast<nsIDOMNodeList*>(docAllList));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// There's only 0 or 1 items. Return the first one or null.
|
||||
NS_IF_ADDREF(*aResult = entry->mDocAllList->Item(0, PR_TRUE));
|
||||
NS_IF_ADDREF(*aResult = docAllList->Item(0, PR_TRUE));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -152,6 +152,8 @@
|
|||
#include "nsEventDispatcher.h"
|
||||
#include "nsPresShellIterator.h"
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "nsIDOMXULCommandEvent.h"
|
||||
#include "nsIDOMNSEvent.h"
|
||||
|
||||
/**
|
||||
* Three bits are used for XUL Element's lazy state.
|
||||
|
@ -1648,6 +1650,22 @@ nsXULElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
|||
EmptyString(),
|
||||
&aVisitor.mDOMEvent);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNSEvent> nsevent =
|
||||
do_QueryInterface(aVisitor.mDOMEvent);
|
||||
while (nsevent) {
|
||||
nsCOMPtr<nsIDOMEventTarget> oTarget;
|
||||
nsevent->GetOriginalTarget(getter_AddRefs(oTarget));
|
||||
NS_ENSURE_STATE(!SameCOMIdentity(oTarget, commandContent));
|
||||
nsCOMPtr<nsIDOMEvent> tmp;
|
||||
nsCOMPtr<nsIDOMXULCommandEvent> commandEvent =
|
||||
do_QueryInterface(nsevent);
|
||||
if (commandEvent) {
|
||||
commandEvent->GetSourceEvent(getter_AddRefs(tmp));
|
||||
}
|
||||
nsevent = do_QueryInterface(tmp);
|
||||
}
|
||||
|
||||
event.sourceEvent = aVisitor.mDOMEvent;
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
|
|
|
@ -406,7 +406,7 @@ interface nsIDOMCSS2Properties : nsISupports
|
|||
// raises(DOMException) on setting
|
||||
};
|
||||
|
||||
[scriptable, uuid(c9339b8c-9bdd-4d2a-a61a-55ca609b92bd)]
|
||||
[scriptable, uuid(8a5b178d-c805-4f8e-8992-fa7c5c11d08e)]
|
||||
interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties
|
||||
{
|
||||
/* Non-DOM 2 extensions */
|
||||
|
@ -591,4 +591,6 @@ interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties
|
|||
attribute DOMString MozBorderStartWidth;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
attribute DOMString MozStackSizing;
|
||||
// raises(DOMException) on setting
|
||||
};
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// Tests conversion of a single byte from UTF-16 to Unicode
|
||||
|
||||
const inString = "A";
|
||||
|
||||
const expectedString = "\ufffd";
|
||||
|
||||
const charset = "UTF-16BE";
|
||||
|
||||
function run_test() {
|
||||
var ScriptableUnicodeConverter =
|
||||
Components.Constructor("@mozilla.org/intl/scriptableunicodeconverter",
|
||||
"nsIScriptableUnicodeConverter");
|
||||
|
||||
var converter = new ScriptableUnicodeConverter();
|
||||
converter.charset = charset;
|
||||
try {
|
||||
var outString = converter.ConvertToUnicode(inString) + converter.Finish();
|
||||
} catch(e) {
|
||||
outString = "\ufffd";
|
||||
}
|
||||
do_check_eq(outString, expectedString);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
// Tests encoding of characters below U+0020
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const inString = "Hello\u000aWorld";
|
||||
const expectedString = "Hello\nWorld";
|
||||
|
||||
|
||||
function run_test() {
|
||||
var failures = false;
|
||||
var ccManager = Cc["@mozilla.org/charset-converter-manager;1"]
|
||||
.getService(Ci.nsICharsetConverterManager);
|
||||
var encodingConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
|
||||
var charsetList = ccManager.getDecoderList();
|
||||
var counter = 0;
|
||||
while (charsetList.hasMore()) {
|
||||
++counter;
|
||||
var charset = charsetList.getNext();
|
||||
|
||||
// exclude known non-ASCII compatible charsets
|
||||
if (charset.substr(0, "UTF-16".length) == "UTF-16" ||
|
||||
charset.substr(0, "UTF-32".length) == "UTF-32" ||
|
||||
charset == "x-imap4-modified-utf7") {
|
||||
dump("skipping " + counter + " " + charset + "\n");
|
||||
continue;
|
||||
}
|
||||
dump("testing " + counter + " " + charset + "\n");
|
||||
|
||||
try {
|
||||
encodingConverter.charset = charset;
|
||||
} catch(e) {
|
||||
dump("Warning: couldn't set encoder charset to " + charset + "\n");
|
||||
continue;
|
||||
}
|
||||
var codepageString = encodingConverter.ConvertFromUnicode(inString) +
|
||||
encodingConverter.Finish();
|
||||
if (codepageString != expectedString) {
|
||||
dump(charset + " encoding failed\n");
|
||||
for (var i = 0; i < expectedString.length; ++i) {
|
||||
if (codepageString.charAt(i) != expectedString.charAt(i)) {
|
||||
dump(i.toString(16) + ": 0x" +
|
||||
codepageString.charCodeAt(i).toString(16) + " != " +
|
||||
expectedString.charCodeAt(i).toString(16) + "\n");
|
||||
}
|
||||
}
|
||||
failures = true;
|
||||
}
|
||||
}
|
||||
if (failures) {
|
||||
do_throw("test failed\n");
|
||||
}
|
||||
}
|
|
@ -59,11 +59,13 @@ UTF16ConvertToUnicode(PRUint8& aState, PRUint8& aData, const char * aSrc,
|
|||
|
||||
if(STATE_FOUND_BOM == aState) // caller found a BOM
|
||||
{
|
||||
NS_ASSERTION(*aSrcLength >= 2, "Too few bytes in input");
|
||||
if (*aSrcLength < 2)
|
||||
return NS_ERROR_ILLEGAL_INPUT;
|
||||
src+=2;
|
||||
aState = STATE_NORMAL;
|
||||
} else if(STATE_FIRST_CALL == aState) { // first time called
|
||||
NS_ASSERTION(*aSrcLength >= 2, "Too few bytes in input");
|
||||
if (*aSrcLength < 2)
|
||||
return NS_ERROR_ILLEGAL_INPUT;
|
||||
|
||||
// Eliminate BOM (0xFEFF). Note that different endian case is taken care of
|
||||
// in |Convert| of LE and BE converters. Here, we only have to
|
||||
|
@ -159,7 +161,8 @@ nsUTF16BEToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength,
|
|||
if(STATE_FIRST_CALL == mState) // Called for the first time.
|
||||
{
|
||||
mState = STATE_NORMAL;
|
||||
NS_ASSERTION(*aSrcLength >= 2, "Too few bytes in input");
|
||||
if (*aSrcLength < 2)
|
||||
return NS_ERROR_ILLEGAL_INPUT;
|
||||
if(0xFFFE == *((PRUnichar*)aSrc)) {
|
||||
// eliminate BOM (on LE machines, BE BOM is 0xFFFE)
|
||||
mState = STATE_FOUND_BOM;
|
||||
|
@ -190,7 +193,8 @@ nsUTF16LEToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength,
|
|||
if(STATE_FIRST_CALL == mState) // first time called
|
||||
{
|
||||
mState = STATE_NORMAL;
|
||||
NS_ASSERTION(*aSrcLength >= 2, "Too few bytes in input");
|
||||
if (*aSrcLength < 2)
|
||||
return NS_ERROR_ILLEGAL_INPUT;
|
||||
if(0xFFFE == *((PRUnichar*)aSrc)) {
|
||||
// eliminate BOM (on BE machines, LE BOM is 0xFFFE)
|
||||
mState = STATE_FOUND_BOM;
|
||||
|
@ -226,7 +230,8 @@ nsUTF16ToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength,
|
|||
if(STATE_FIRST_CALL == mState) // first time called
|
||||
{
|
||||
mState = STATE_NORMAL;
|
||||
NS_ASSERTION(*aSrcLength >= 2, "Too few bytes in input");
|
||||
if (*aSrcLength < 2)
|
||||
return NS_ERROR_ILLEGAL_INPUT;
|
||||
|
||||
// check if BOM (0xFEFF) is at the beginning, remove it if found, and
|
||||
// set mEndian accordingly.
|
||||
|
|
|
@ -62,8 +62,13 @@ nsresult nsUnicodeEncodeHelper::ConvertByTable(
|
|||
|
||||
while (src < srcEnd) {
|
||||
if (!uMapCode((uTable*) aMappingTable, static_cast<PRUnichar>(*(src++)), reinterpret_cast<PRUint16*>(&med))) {
|
||||
res = NS_ERROR_UENC_NOMAPPING;
|
||||
break;
|
||||
if (*(src - 1) < 0x20) {
|
||||
// some tables are missing the 0x00 - 0x20 part
|
||||
med = *(src - 1);
|
||||
} else {
|
||||
res = NS_ERROR_UENC_NOMAPPING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool charFound;
|
||||
|
|
|
@ -178,6 +178,24 @@ js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
|
|||
return !_check_lock((atomic_p)w, ov, nv);
|
||||
}
|
||||
|
||||
#elif defined(USE_ARM_KUSER)
|
||||
|
||||
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=429387 for a
|
||||
* description of this ABI; this is a function provided at a fixed
|
||||
* location by the kernel in the memory space of each process.
|
||||
*/
|
||||
typedef int (__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
|
||||
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(jsword) == sizeof(int));
|
||||
|
||||
static JS_INLINE int
|
||||
js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
|
||||
{
|
||||
volatile int *vp = (volatile int*)w;
|
||||
return !__kernel_cmpxchg(ov, nv, vp);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error "Define NSPR_LOCK if your platform lacks a compare-and-swap instruction."
|
||||
|
|
|
@ -226,7 +226,7 @@ extern void js_SetScopeInfo(JSScope *scope, const char *file, int line);
|
|||
!( (defined(_WIN32) && defined(_M_IX86)) || \
|
||||
(defined(__GNUC__) && defined(__i386__)) || \
|
||||
(defined(SOLARIS) && defined(sparc) && defined(ULTRA_SPARC)) || \
|
||||
defined(AIX) )
|
||||
defined(AIX) || defined(USE_ARM_KUSER))
|
||||
|
||||
#define NSPR_LOCK 1
|
||||
|
||||
|
|
|
@ -128,6 +128,10 @@
|
|||
#define NS_STYLE_BOX_ORIENT_HORIZONTAL 0
|
||||
#define NS_STYLE_BOX_ORIENT_VERTICAL 1
|
||||
|
||||
// stack-sizing
|
||||
#define NS_STYLE_STACK_SIZING_IGNORE 0
|
||||
#define NS_STYLE_STACK_SIZING_STRETCH_TO_FIT 1
|
||||
|
||||
// Azimuth - See nsStyleAural
|
||||
#define NS_STYLE_AZIMUTH_LEFT_SIDE 0x00
|
||||
#define NS_STYLE_AZIMUTH_FAR_LEFT 0x01
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<window
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3c.org/1999/xhtml"
|
||||
width="400"
|
||||
height="600">
|
||||
|
||||
<vbox>
|
||||
<hbox style="height: 20px;">
|
||||
<spacer style="width: 100px; background: yellow;"/>
|
||||
<spacer style="width: 100px; background: blue;"/>
|
||||
<spacer style="width: 50px; background: yellow;"/>
|
||||
<spacer style="width: 150px; background: green;"/>
|
||||
</hbox>
|
||||
|
||||
<hbox style="height: 20px;">
|
||||
<spacer style="width: 100px; background: yellow;"/>
|
||||
<spacer style="width: 100px; background: blue;"/>
|
||||
<spacer style="width: 50px; background: yellow;"/>
|
||||
<spacer style="width: 150px; background: green;"/>
|
||||
</hbox>
|
||||
|
||||
<hbox style="height: 20px;">
|
||||
<spacer style="width: 100px; background: yellow;"/>
|
||||
<spacer style="width: 100px; background: blue;"/>
|
||||
<spacer style="width: 50px; background: yellow;"/>
|
||||
<spacer style="width: 150px; background: green;"/>
|
||||
</hbox>
|
||||
|
||||
<hbox style="height: 20px;">
|
||||
<spacer style="width: 100px; background: yellow;"/>
|
||||
<spacer style="width: 100px; background: blue;"/>
|
||||
<spacer style="width: 200px; background: green;"/>
|
||||
</hbox>
|
||||
|
||||
<hbox style="height: 20px;">
|
||||
<spacer style="width: 100px; background: yellow;"/>
|
||||
<spacer style="width: 300px; background: green;"/>
|
||||
</hbox>
|
||||
|
||||
<hbox style="height: 20px;">
|
||||
<spacer style="width: 200px; background: yellow;"/>
|
||||
<spacer style="width: 200px; background: green;"/>
|
||||
</hbox>
|
||||
|
||||
<hbox style="height: 20px;">
|
||||
<spacer style="width: 100px; background: yellow;"/>
|
||||
<spacer style="width: 300px; background: green;"/>
|
||||
</hbox>
|
||||
|
||||
</vbox>
|
||||
|
||||
</window>
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<window
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3c.org/1999/xhtml"
|
||||
width="400"
|
||||
height="600">
|
||||
|
||||
<vbox style="max-width: 400px;">
|
||||
<!-- default: the inner hbox should expand the stack. -->
|
||||
<hbox style="height: 20px;">
|
||||
<stack flex="1" style="background: yellow;">
|
||||
<hbox style="width: 100px; height: 20px; background: blue;" top="0" left="100"/>
|
||||
</stack>
|
||||
<spacer flex="3" style="background: green;"/>
|
||||
</hbox>
|
||||
|
||||
<!-- same as above, with explicit -moz-stack-sizing: stretch-to-fit -->
|
||||
<hbox style="height: 20px;">
|
||||
<stack flex="1" style="background: yellow;">
|
||||
<hbox style="-moz-stack-sizing: stretch-to-fit; width: 100px; height: 20px; background: blue;" top="0" left="100"/>
|
||||
</stack>
|
||||
<spacer flex="3" style="background: green;"/>
|
||||
</hbox>
|
||||
|
||||
<!-- same as above, but with overflow: hidden -->
|
||||
<hbox style="height: 20px;">
|
||||
<stack flex="1" style="overflow: hidden; background: yellow;">
|
||||
<hbox style="-moz-stack-sizing: stretch-to-fit; width: 100px; height: 20px; background: blue;" top="0" left="100"/>
|
||||
</stack>
|
||||
<spacer flex="3" style="background: green; height: 20px;"/>
|
||||
</hbox>
|
||||
|
||||
<!-- inner hbox has stack-sizing: ignore, but the stack doesn't have overflow: hidden set; the stack will stretch
|
||||
just enough to include the child, but no more -->
|
||||
<hbox style="height: 20px;">
|
||||
<stack flex="1" style="background: yellow;">
|
||||
<hbox style="-moz-stack-sizing: ignore; width: 100px; height: 20px; background: blue;" top="0" left="100"/>
|
||||
</stack>
|
||||
<spacer flex="3" style="background: green; height: 20px;"/>
|
||||
</hbox>
|
||||
|
||||
<!-- same as above, except stack has overflow: hidden set, so the blue shouldn't be visible -->
|
||||
<hbox style="height: 20px;">
|
||||
<stack flex="1" style="overflow: hidden; background: yellow;">
|
||||
<hbox style="-moz-stack-sizing: ignore; width: 100px; height: 20px; background: blue;" top="0" left="100"/>
|
||||
</stack>
|
||||
<spacer flex="3" style="background: green; height: 20px;"/>
|
||||
</hbox>
|
||||
|
||||
<!-- no flex on the stack, but an explicit size; the child will cause us to resize the stack during Layout -->
|
||||
<hbox style="height: 20px;">
|
||||
<stack style="width: 100px; background: yellow;">
|
||||
<hbox style="width: 100px; height: 20px; background: transparent;" top="0" left="100"/>
|
||||
</stack>
|
||||
<spacer flex="1" style="background: green;"/>
|
||||
</hbox>
|
||||
|
||||
<!-- same as above, but with stack-sizing: ignore; the stack should not be resized -->
|
||||
<hbox style="height: 20px;">
|
||||
<stack style="width: 100px; background: yellow;">
|
||||
<hbox style="-moz-stack-sizing: ignore; width: 100px; height: 20px; background: transparent;" top="0" left="100"/>
|
||||
</stack>
|
||||
<spacer flex="1" style="background: green;"/>
|
||||
</hbox>
|
||||
|
||||
</vbox>
|
||||
|
||||
</window>
|
|
@ -301,6 +301,7 @@ random-if(MOZ_WIDGET_TOOLKIT=="gtk2") == 333970-1.html 333970-1-ref.html # bug 3
|
|||
== 345267-1c.html 345267-1-ref.html
|
||||
== 345267-1d.html 345267-1-ref.html
|
||||
!= 345563-sub.xhtml 345563-sup.xhtml
|
||||
== 346189-1.xul 346189-1-ref.xul
|
||||
== 346774-1a.html 346774-1-ref.html
|
||||
== 346774-1b.html 346774-1-ref.html
|
||||
== 346774-1c.html 346774-1-ref.html
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
p:first-letter {
|
||||
float: left;
|
||||
}
|
||||
</style>
|
||||
<title>a first-letter testcase</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Lorem ipsum dolor sit amet.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
p:first-letter {
|
||||
float: left;
|
||||
}
|
||||
</style>
|
||||
<title>a first-letter testcase</title>
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
document.getElementsByTagName("style")[0].disabled = true;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Lorem ipsum dolor sit amet.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>a first-letter testcase</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Lorem ipsum dolor sit amet.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -29,5 +29,7 @@ random == dynamic-3b.html dynamic-3-ref.html
|
|||
== 23605-5.html 23605-5-ref.html
|
||||
== 23605-6.html 23605-6-ref.html
|
||||
random-if(MOZ_WIDGET_TOOLKIT=="gtk2") == 329069-1.html 329069-1-ref.html # failure is font-dependent, may be related to bug 404848
|
||||
!= 229764-1.html 229764-ref.html
|
||||
== 229764-2.html 229764-ref.html
|
||||
== 342120-1.xhtml 342120-1-ref.xhtml
|
||||
== 379799-1.html 379799-1-ref.html
|
||||
|
|
|
@ -418,6 +418,7 @@ CSS_KEY(start, start)
|
|||
CSS_KEY(static, static)
|
||||
CSS_KEY(status-bar, status_bar)
|
||||
CSS_KEY(stretch, stretch)
|
||||
CSS_KEY(stretch-to-fit, stretch_to_fit)
|
||||
CSS_KEY(sub, sub)
|
||||
CSS_KEY(super, super)
|
||||
CSS_KEY(sw-resize, sw_resize)
|
||||
|
|
|
@ -5070,6 +5070,9 @@ PRBool CSSParserImpl::ParseSingleValueProperty(nsresult& aErrorCode,
|
|||
case eCSSProperty_speech_rate:
|
||||
return ParseVariant(aErrorCode, aValue, VARIANT_HN | VARIANT_KEYWORD,
|
||||
nsCSSProps::kSpeechRateKTable);
|
||||
case eCSSProperty_stack_sizing:
|
||||
return ParseVariant(aErrorCode, aValue, VARIANT_HK,
|
||||
nsCSSProps::kStackSizingKTable);
|
||||
case eCSSProperty_stress:
|
||||
return ParseVariant(aErrorCode, aValue, VARIANT_HN, nsnull);
|
||||
case eCSSProperty_table_layout:
|
||||
|
|
|
@ -516,6 +516,7 @@ CSS_PROP_XUL(-moz-box-flex, box_flex, MozBoxFlex, XUL, mBoxFlex, eCSSType_Value,
|
|||
CSS_PROP_XUL(-moz-box-orient, box_orient, MozBoxOrient, XUL, mBoxOrient, eCSSType_Value, kBoxOrientKTable) // XXX bug 3935
|
||||
CSS_PROP_XUL(-moz-box-pack, box_pack, MozBoxPack, XUL, mBoxPack, eCSSType_Value, kBoxPackKTable) // XXX bug 3935
|
||||
CSS_PROP_XUL(-moz-box-ordinal-group, box_ordinal_group, MozBoxOrdinalGroup, XUL, mBoxOrdinal, eCSSType_Value, nsnull)
|
||||
CSS_PROP_XUL(-moz-stack-sizing, stack_sizing, MozStackSizing, XUL, mStackSizing, eCSSType_Value, kStackSizingKTable)
|
||||
|
||||
#ifdef MOZ_MATHML
|
||||
#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
|
||||
|
|
|
@ -860,6 +860,12 @@ const PRInt32 nsCSSProps::kSpeechRateKTable[] = {
|
|||
eCSSKeyword_UNKNOWN,-1
|
||||
};
|
||||
|
||||
const PRInt32 nsCSSProps::kStackSizingKTable[] = {
|
||||
eCSSKeyword_ignore, NS_STYLE_STACK_SIZING_IGNORE,
|
||||
eCSSKeyword_stretch_to_fit, NS_STYLE_STACK_SIZING_STRETCH_TO_FIT,
|
||||
eCSSKeyword_UNKNOWN,-1
|
||||
};
|
||||
|
||||
const PRInt32 nsCSSProps::kTableLayoutKTable[] = {
|
||||
eCSSKeyword_fixed, NS_STYLE_TABLE_LAYOUT_FIXED,
|
||||
eCSSKeyword_UNKNOWN,-1
|
||||
|
|
|
@ -177,6 +177,7 @@ public:
|
|||
static const PRInt32 kSpeakNumeralKTable[];
|
||||
static const PRInt32 kSpeakPunctuationKTable[];
|
||||
static const PRInt32 kSpeechRateKTable[];
|
||||
static const PRInt32 kStackSizingKTable[];
|
||||
static const PRInt32 kTableLayoutKTable[];
|
||||
static const PRInt32 kTextAlignKTable[];
|
||||
static const PRInt32 kTextDecorationKTable[];
|
||||
|
|
|
@ -548,6 +548,7 @@ struct nsCSSXUL : public nsCSSStruct {
|
|||
nsCSSValue mBoxOrient;
|
||||
nsCSSValue mBoxPack;
|
||||
nsCSSValue mBoxOrdinal;
|
||||
nsCSSValue mStackSizing;
|
||||
private:
|
||||
nsCSSXUL(const nsCSSXUL& aOther); // NOT IMPLEMENTED
|
||||
};
|
||||
|
|
|
@ -486,6 +486,18 @@ nsComputedDOMStyle::GetBottom(nsIDOMCSSValue** aValue)
|
|||
return GetOffsetWidthFor(NS_SIDE_BOTTOM, aValue);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComputedDOMStyle::GetStackSizing(nsIDOMCSSValue** aValue)
|
||||
{
|
||||
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
|
||||
NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
val->SetIdent(GetStyleXUL()->mStretchStack ? nsGkAtoms::stretch_to_fit :
|
||||
nsGkAtoms::ignore);
|
||||
|
||||
return CallQueryInterface(val, aValue);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue* aValue,
|
||||
nscolor aColor)
|
||||
|
@ -3806,6 +3818,7 @@ nsComputedDOMStyle::GetQueryablePropertyMap(PRUint32* aLength)
|
|||
COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_bottomRight,OutlineRadiusBottomRight),
|
||||
COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_topLeft, OutlineRadiusTopLeft),
|
||||
COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_topRight, OutlineRadiusTopRight),
|
||||
COMPUTED_STYLE_MAP_ENTRY(stack_sizing, StackSizing),
|
||||
COMPUTED_STYLE_MAP_ENTRY(user_focus, UserFocus),
|
||||
COMPUTED_STYLE_MAP_ENTRY(user_input, UserInput),
|
||||
COMPUTED_STYLE_MAP_ENTRY(user_modify, UserModify),
|
||||
|
|
|
@ -133,6 +133,7 @@ private:
|
|||
nsresult GetTop(nsIDOMCSSValue** aValue);
|
||||
nsresult GetRight(nsIDOMCSSValue** aValue);
|
||||
nsresult GetBottom(nsIDOMCSSValue** aValue);
|
||||
nsresult GetStackSizing(nsIDOMCSSValue** aValue);
|
||||
|
||||
/* Font properties */
|
||||
nsresult GetColor(nsIDOMCSSValue** aValue);
|
||||
|
|
|
@ -4525,6 +4525,16 @@ nsRuleNode::ComputeXULData(void* aStartStruct,
|
|||
xul->mBoxOrdinal = 1;
|
||||
}
|
||||
|
||||
if (eCSSUnit_Inherit == xulData.mStackSizing.GetUnit()) {
|
||||
inherited = PR_TRUE;
|
||||
xul->mStretchStack = parentXUL->mStretchStack;
|
||||
} else if (eCSSUnit_Initial == xulData.mStackSizing.GetUnit()) {
|
||||
xul->mStretchStack = PR_TRUE;
|
||||
} else if (eCSSUnit_Enumerated == xulData.mStackSizing.GetUnit()) {
|
||||
xul->mStretchStack = xulData.mStackSizing.GetIntValue() ==
|
||||
NS_STYLE_STACK_SIZING_STRETCH_TO_FIT;
|
||||
}
|
||||
|
||||
COMPUTE_END_RESET(XUL, xul)
|
||||
}
|
||||
|
||||
|
|
|
@ -573,6 +573,7 @@ nsStyleXUL::nsStyleXUL()
|
|||
mBoxOrient = NS_STYLE_BOX_ORIENT_HORIZONTAL;
|
||||
mBoxPack = NS_STYLE_BOX_PACK_START;
|
||||
mBoxOrdinal = 1;
|
||||
mStretchStack = PR_TRUE;
|
||||
}
|
||||
|
||||
nsStyleXUL::~nsStyleXUL()
|
||||
|
|
|
@ -1187,6 +1187,7 @@ struct nsStyleXUL {
|
|||
PRUint8 mBoxDirection; // [reset] see nsStyleConsts.h
|
||||
PRUint8 mBoxOrient; // [reset] see nsStyleConsts.h
|
||||
PRUint8 mBoxPack; // [reset] see nsStyleConsts.h
|
||||
PRPackedBool mStretchStack; // [reset] see nsStyleConsts.h
|
||||
};
|
||||
|
||||
struct nsStyleColumn {
|
||||
|
|
|
@ -442,6 +442,14 @@ var gCSSProperties = {
|
|||
other_values: [ "1px", "3em" ],
|
||||
invalid_values: []
|
||||
},
|
||||
"-moz-stack-sizing": {
|
||||
domProp: "MozStackSizing",
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: [ "stretch-to-fit" ],
|
||||
other_values: [ "ignore" ],
|
||||
invalid_values: []
|
||||
},
|
||||
"-moz-user-focus": {
|
||||
domProp: "MozUserFocus",
|
||||
inherited: true,
|
||||
|
|
|
@ -76,29 +76,35 @@ nsStackLayout::nsStackLayout()
|
|||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Sizing: we are as wide as the widest child plus its left offset
|
||||
* we are tall as the tallest child plus its top offset.
|
||||
*
|
||||
* Only children which have -moz-stack-sizing set to stretch-to-fit
|
||||
* (the default) will be included in the size computations.
|
||||
*/
|
||||
|
||||
nsSize
|
||||
nsStackLayout::GetPrefSize(nsIBox* aBox, nsBoxLayoutState& aState)
|
||||
{
|
||||
nsSize rpref (0, 0);
|
||||
|
||||
// we are as wide as the widest child plus its left offset
|
||||
// we are tall as the tallest child plus its top offset
|
||||
nsSize prefSize (0, 0);
|
||||
|
||||
nsIBox* child = aBox->GetChildBox();
|
||||
while (child) {
|
||||
nsSize pref = child->GetPrefSize(aState);
|
||||
while (child) {
|
||||
if (child->GetStyleXUL()->mStretchStack) {
|
||||
nsSize pref = child->GetPrefSize(aState);
|
||||
|
||||
AddMargin(child, pref);
|
||||
AddOffset(aState, child, pref);
|
||||
AddLargestSize(rpref, pref);
|
||||
AddMargin(child, pref);
|
||||
AddOffset(aState, child, pref);
|
||||
AddLargestSize(prefSize, pref);
|
||||
}
|
||||
|
||||
child = child->GetNextBox();
|
||||
}
|
||||
|
||||
// now add our border and padding
|
||||
AddBorderAndPadding(aBox, rpref);
|
||||
AddBorderAndPadding(aBox, prefSize);
|
||||
|
||||
return rpref;
|
||||
return prefSize;
|
||||
}
|
||||
|
||||
nsSize
|
||||
|
@ -106,19 +112,19 @@ nsStackLayout::GetMinSize(nsIBox* aBox, nsBoxLayoutState& aState)
|
|||
{
|
||||
nsSize minSize (0, 0);
|
||||
|
||||
// run through all the children and get their min, max, and preferred sizes
|
||||
|
||||
nsIBox* child = aBox->GetChildBox();
|
||||
while (child) {
|
||||
nsSize min = child->GetMinSize(aState);
|
||||
AddMargin(child, min);
|
||||
AddOffset(aState, child, min);
|
||||
AddLargestSize(minSize, min);
|
||||
while (child) {
|
||||
if (child->GetStyleXUL()->mStretchStack) {
|
||||
nsSize min = child->GetMinSize(aState);
|
||||
|
||||
AddMargin(child, min);
|
||||
AddOffset(aState, child, min);
|
||||
AddLargestSize(minSize, min);
|
||||
}
|
||||
|
||||
child = child->GetNextBox();
|
||||
}
|
||||
|
||||
// now add our border and padding
|
||||
AddBorderAndPadding(aBox, minSize);
|
||||
|
||||
return minSize;
|
||||
|
@ -129,21 +135,22 @@ nsStackLayout::GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aState)
|
|||
{
|
||||
nsSize maxSize (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
|
||||
|
||||
// run through all the children and get their min, max, and preferred sizes
|
||||
|
||||
nsIBox* child = aBox->GetChildBox();
|
||||
while (child) {
|
||||
nsSize min = child->GetMinSize(aState);
|
||||
nsSize max = nsBox::BoundsCheckMinMax(min, child->GetMaxSize(aState));
|
||||
while (child) {
|
||||
if (child->GetStyleXUL()->mStretchStack) {
|
||||
nsSize min = child->GetMinSize(aState);
|
||||
nsSize max = child->GetMaxSize(aState);
|
||||
|
||||
AddMargin(child, max);
|
||||
AddOffset(aState, child, max);
|
||||
AddSmallestSize(maxSize, max);
|
||||
max = nsBox::BoundsCheckMinMax(min, max);
|
||||
|
||||
AddMargin(child, max);
|
||||
AddOffset(aState, child, max);
|
||||
AddSmallestSize(maxSize, max);
|
||||
}
|
||||
|
||||
child = child->GetNextBox();
|
||||
}
|
||||
|
||||
// now add our border and padding
|
||||
AddBorderAndPadding(aBox, maxSize);
|
||||
|
||||
return maxSize;
|
||||
|
@ -292,15 +299,17 @@ nsStackLayout::Layout(nsIBox* aBox, nsBoxLayoutState& aState)
|
|||
childRectNoMargin = childRect = child->GetRect();
|
||||
childRect.Inflate(margin);
|
||||
|
||||
// Did the child push back on us and get bigger?
|
||||
if (offset.width + childRect.width > clientRect.width) {
|
||||
clientRect.width = childRect.width + offset.width;
|
||||
grow = PR_TRUE;
|
||||
}
|
||||
if (child->GetStyleXUL()->mStretchStack) {
|
||||
// Did the child push back on us and get bigger?
|
||||
if (offset.width + childRect.width > clientRect.width) {
|
||||
clientRect.width = childRect.width + offset.width;
|
||||
grow = PR_TRUE;
|
||||
}
|
||||
|
||||
if (offset.height + childRect.height > clientRect.height) {
|
||||
clientRect.height = childRect.height + offset.height;
|
||||
grow = PR_TRUE;
|
||||
if (offset.height + childRect.height > clientRect.height) {
|
||||
clientRect.height = childRect.height + offset.height;
|
||||
grow = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (childRectNoMargin != oldRect)
|
||||
|
|
|
@ -1,3 +1,42 @@
|
|||
// ***** 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 the Public Suffix List.
|
||||
//
|
||||
// The Initial Developer of the Original Code is
|
||||
// Jo Hermans <jo.hermans@gmail.com>.
|
||||
// Portions created by the Initial Developer are Copyright (C) 2007
|
||||
// the Initial Developer. All Rights Reserved.
|
||||
//
|
||||
// Contributor(s):
|
||||
// Ruben Arakelyan <ruben@wackomenace.co.uk>
|
||||
//
|
||||
// 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 *****
|
||||
|
||||
// $Id$
|
||||
|
||||
// ac : http://en.wikipedia.org/wiki/.ac
|
||||
ac
|
||||
com.ac
|
||||
|
|
|
@ -10,6 +10,8 @@ include('unstable/adts.js');
|
|||
include('unstable/analysis.js');
|
||||
include('unstable/esp.js');
|
||||
include('unstable/liveness.js');
|
||||
let Zero_NonZero = {};
|
||||
include('unstable/zero_nonzero.js', Zero_NonZero);
|
||||
|
||||
include('mayreturn.js');
|
||||
|
||||
|
@ -148,7 +150,8 @@ function OutparamCheck(cfg, psem_list, outparam_list, retvar, retvar_set, finall
|
|||
print(" " + expr_display(v));
|
||||
}
|
||||
}
|
||||
ESP.Analysis.call(this, cfg, this.psvar_list, av.BOTTOM, av.meet, trace);
|
||||
this.zeroNonzero = new Zero_NonZero.Zero_NonZero();
|
||||
ESP.Analysis.call(this, cfg, this.psvar_list, av.meet, trace);
|
||||
}
|
||||
|
||||
// Abstract values for outparam check
|
||||
|
@ -165,10 +168,11 @@ AbstractValue.prototype.toString = function() {
|
|||
return this.name + ' (' + this.ch + ')';
|
||||
}
|
||||
|
||||
let avspec = [
|
||||
// General-purpose abstract values
|
||||
[ 'BOTTOM', '.' ], // any value, also used for dead vars
|
||||
AbstractValue.prototype.toShortString = function() {
|
||||
return this.ch;
|
||||
}
|
||||
|
||||
let avspec = [
|
||||
// Abstract values for outparam contents write status
|
||||
[ 'NULL', 'x' ], // is a null pointer
|
||||
[ 'NOT_WRITTEN', '-' ], // not written
|
||||
|
@ -180,10 +184,6 @@ let avspec = [
|
|||
// in last position), so if there is an error with it not being written,
|
||||
// we can give a hint about the possible outparam in the warning.
|
||||
[ 'MAYBE_WRITTEN', '?' ], // written if possible outparam is one
|
||||
|
||||
// Abstract values for rvs
|
||||
[ 'ZERO', '0' ], // zero value
|
||||
[ 'NONZERO', '1' ] // nonzero value
|
||||
];
|
||||
|
||||
let av = {};
|
||||
|
@ -191,11 +191,13 @@ for each (let [name, ch] in avspec) {
|
|||
av[name] = new AbstractValue(name, ch);
|
||||
}
|
||||
|
||||
av.ZERO = Zero_NonZero.Lattice.ZERO;
|
||||
av.NONZERO = Zero_NonZero.Lattice.NONZERO;
|
||||
|
||||
/*
|
||||
av.ZERO.negation = av.NONZERO;
|
||||
av.NONZERO.negation = av.ZERO;
|
||||
|
||||
let cachedAVs = {};
|
||||
|
||||
// Abstract values for int constants. We use these to figure out feasible
|
||||
// paths in the presence of GCC finally_tmp-controlled switches.
|
||||
function makeIntAV(v) {
|
||||
|
@ -207,13 +209,16 @@ function makeIntAV(v) {
|
|||
ans.int_val = v;
|
||||
return ans;
|
||||
}
|
||||
*/
|
||||
|
||||
let cachedAVs = {};
|
||||
|
||||
// Abstract values for pointers that contain a copy of an outparam
|
||||
// pointer. We use these to figure out writes to a casted copy of
|
||||
// an outparam passed to another method.
|
||||
function makeOutparamAV(v) {
|
||||
let key = 'outparam_' + DECL_UID(v);
|
||||
if (cachedAVs.hasOwnProperty(key)) return cachedAVs[key];
|
||||
if (key in cachedAVs) return cachedAVs[key];
|
||||
|
||||
let ans = cachedAVs[key] =
|
||||
new AbstractValue('OUTPARAM:' + expr_display(v), 'P');
|
||||
|
@ -230,31 +235,14 @@ av.intVal = function(v) {
|
|||
|
||||
/** Meet function for our abstract values. */
|
||||
av.meet = function(v1, v2) {
|
||||
// Important for following cases -- as output, undefined means top here.
|
||||
if (v1 == undefined) v1 = av.BOTTOM;
|
||||
if (v2 == undefined) v2 = av.BOTTOM;
|
||||
|
||||
// These cases apply for any lattice.
|
||||
if (v1 == av.BOTTOM) return v2;
|
||||
if (v2 == av.BOTTOM) return v1;
|
||||
if (v1 == v2) return v1;
|
||||
|
||||
// At this point we know v1 != v2.
|
||||
switch (v1) {
|
||||
case av.ZERO:
|
||||
return av.intVal(v2) == 0 ? v2 : undefined;
|
||||
case av.NONZERO:
|
||||
// Return a nonempty meet only if the other value is an integer
|
||||
// and is nonzero.
|
||||
let iv2 = av.intVal(v2);
|
||||
return iv2 != undefined && iv2 != 0 ? v2 : undefined;
|
||||
default:
|
||||
let iv = av.intVal(v1);
|
||||
if (iv == 0) return v2 == av.ZERO ? v1 : undefined;
|
||||
if (iv != undefined) return v2 == av.NONZERO ? v1 : undefined;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
let values = [v1,v2]
|
||||
if (values.indexOf(av.LOCKED) != -1
|
||||
|| values.indexOf(av.UNLOCKED) != -1)
|
||||
return ESP.NOT_REACHED;
|
||||
|
||||
return Zero_NonZero.meet(v1, v2)
|
||||
};
|
||||
|
||||
// Outparam check analysis
|
||||
OutparamCheck.prototype = new ESP.Analysis;
|
||||
|
@ -262,11 +250,17 @@ OutparamCheck.prototype = new ESP.Analysis;
|
|||
OutparamCheck.prototype.startValues = function() {
|
||||
let ans = create_decl_map();
|
||||
for each (let p in this.psvar_list) {
|
||||
ans.put(p, this.outparams.has(p) ? av.NOT_WRITTEN : av.BOTTOM);
|
||||
ans.put(p, this.outparams.has(p) ? av.NOT_WRITTEN : ESP.TOP);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
OutparamCheck.prototype.split = function(vbl, v) {
|
||||
// Can't happen for current version of ESP, but could change
|
||||
if (v != ESP.TOP) throw new Error("not implemented");
|
||||
return [ av.ZERO, av.NONZERO ];
|
||||
}
|
||||
|
||||
OutparamCheck.prototype.updateEdgeState = function(e) {
|
||||
e.state.keepOnly(e.dest.keepVars);
|
||||
}
|
||||
|
@ -283,93 +277,17 @@ OutparamCheck.prototype.flowState = function(isn, state) {
|
|||
case COND_EXPR:
|
||||
// This gets handled by flowStateCond instead, has no exec effect
|
||||
break;
|
||||
case RETURN_EXPR:
|
||||
let op = isn.operands()[0];
|
||||
if (op) this.processAssign(isn.operands()[0], state);
|
||||
break;
|
||||
case LABEL_EXPR:
|
||||
case RESX_EXPR:
|
||||
case ASM_EXPR:
|
||||
// NOPs for us
|
||||
break;
|
||||
default:
|
||||
print(TREE_CODE(isn));
|
||||
throw new Error("ni");
|
||||
this.zeroNonzero.flowState(isn, state);
|
||||
}
|
||||
}
|
||||
|
||||
OutparamCheck.prototype.flowStateCond = function(isn, truth, state) {
|
||||
switch (TREE_CODE(isn)) {
|
||||
case COND_EXPR:
|
||||
this.flowStateIf(isn, truth, state);
|
||||
break;
|
||||
case SWITCH_EXPR:
|
||||
this.flowStateSwitch(isn, truth, state);
|
||||
break;
|
||||
default:
|
||||
throw new Error("ni " + TREE_CODE(isn));
|
||||
}
|
||||
this.zeroNonzero.flowStateCond(isn, truth, state);
|
||||
}
|
||||
|
||||
OutparamCheck.prototype.flowStateIf = function(isn, truth, state) {
|
||||
let exp = TREE_OPERAND(isn, 0);
|
||||
|
||||
if (DECL_P(exp)) {
|
||||
this.filter(state, exp, av.NONZERO, truth, isn);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (TREE_CODE(exp)) {
|
||||
case EQ_EXPR:
|
||||
case NE_EXPR:
|
||||
// Handle 'x op <int lit>' pattern only
|
||||
let op1 = TREE_OPERAND(exp, 0);
|
||||
let op2 = TREE_OPERAND(exp, 1);
|
||||
if (expr_literal_int(op1) != undefined) {
|
||||
[op1,op2] = [op2,op1];
|
||||
}
|
||||
if (!DECL_P(op1)) break;
|
||||
if (expr_literal_int(op2) != 0) break;
|
||||
let val = TREE_CODE(exp) == EQ_EXPR ? av.ZERO : av.NONZERO;
|
||||
|
||||
this.filter(state, op1, val, truth, isn);
|
||||
break;
|
||||
default:
|
||||
// Don't care about anything else.
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
OutparamCheck.prototype.flowStateSwitch = function(isn, truth, state) {
|
||||
let exp = TREE_OPERAND(isn, 0);
|
||||
|
||||
if (DECL_P(exp)) {
|
||||
if (truth != null) {
|
||||
this.filter(state, exp, makeIntAV(truth), true, isn);
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw new Error("ni");
|
||||
}
|
||||
|
||||
// Apply a filter to the state. We need to special case it for this analysis
|
||||
// because outparams only care about being a NULL pointer.
|
||||
OutparamCheck.prototype.filter = function(state, vbl, val, truth, blame) {
|
||||
if (truth != true && truth != false) throw new Error("ni " + truth);
|
||||
if (this.outparams.has(vbl)) {
|
||||
// We do need to check for true and false here because other values
|
||||
// could get passed in from switches.
|
||||
if (truth == true && val == av.ZERO || truth == false && val == av.NONZERO) {
|
||||
state.assignValue(vbl, av.NULL, blame);
|
||||
}
|
||||
} else {
|
||||
if (truth == false) {
|
||||
val = val.negation;
|
||||
}
|
||||
state.filter(vbl, val, blame);
|
||||
}
|
||||
};
|
||||
|
||||
// For any outparams-specific semantics, we handle it here and then
|
||||
// return. Otherwise we delegate to the zero-nonzero analysis.
|
||||
OutparamCheck.prototype.processAssign = function(isn, state) {
|
||||
let lhs = isn.operands()[0];
|
||||
let rhs = isn.operands()[1];
|
||||
|
@ -380,40 +298,20 @@ OutparamCheck.prototype.processAssign = function(isn, state) {
|
|||
rhs = rhs.operands()[0];
|
||||
}
|
||||
|
||||
if (DECL_P(rhs)) {
|
||||
if (this.outparams.has(rhs)) {
|
||||
if (DECL_P(rhs) && this.outparams.has(rhs)) {
|
||||
// Copying an outparam pointer. We have to remember this so that
|
||||
// if it is assigned thru later, we pick up the write.
|
||||
state.assignValue(lhs, makeOutparamAV(rhs), isn);
|
||||
} else {
|
||||
state.assign(lhs, rhs, isn);
|
||||
}
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
switch (TREE_CODE(rhs)) {
|
||||
case INTEGER_CST:
|
||||
if (this.outparams.has(lhs)) {
|
||||
warning("assigning to outparam pointer");
|
||||
} else {
|
||||
// Need to know the exact int value for finally_tmp.
|
||||
if (is_finally_tmp(lhs)) {
|
||||
let v = TREE_INT_CST_LOW(rhs);
|
||||
state.assignValue(lhs, makeIntAV(v), isn);
|
||||
} else {
|
||||
let value = expr_literal_int(rhs) == 0 ? av.ZERO : av.NONZERO;
|
||||
state.assignValue(lhs, value, isn);
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case NE_EXPR: {
|
||||
// We only care about gcc-generated x != 0 for conversions and such.
|
||||
let [op1, op2] = rhs.operands();
|
||||
if (DECL_P(op1) && expr_literal_int(op2) == 0) {
|
||||
state.assign(lhs, op1, isn);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EQ_EXPR: {
|
||||
// We only care about testing outparams for NULL (and then not writing)
|
||||
let [op1, op2] = rhs.operands();
|
||||
|
@ -425,6 +323,7 @@ OutparamCheck.prototype.processAssign = function(isn, state) {
|
|||
s2.assignValue(lhs, av.ZERO, isn);
|
||||
return [s1, s2];
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -440,40 +339,18 @@ OutparamCheck.prototype.processAssign = function(isn, state) {
|
|||
} else {
|
||||
this.processCall(lhs, rhs, isn, state);
|
||||
}
|
||||
break;
|
||||
// Stuff we don't analyze -- just kill the LHS info
|
||||
case ADDR_EXPR:
|
||||
case POINTER_PLUS_EXPR:
|
||||
case ARRAY_REF:
|
||||
case COMPONENT_REF:
|
||||
case INDIRECT_REF:
|
||||
case FILTER_EXPR:
|
||||
case EXC_PTR_EXPR:
|
||||
case CONSTRUCTOR:
|
||||
|
||||
case REAL_CST:
|
||||
case STRING_CST:
|
||||
|
||||
case CONVERT_EXPR:
|
||||
case TRUTH_NOT_EXPR:
|
||||
case TRUTH_XOR_EXPR:
|
||||
case BIT_FIELD_REF:
|
||||
state.remove(lhs);
|
||||
break;
|
||||
default:
|
||||
if (UNARY_CLASS_P(rhs) || BINARY_CLASS_P(rhs) || COMPARISON_CLASS_P(rhs)) {
|
||||
state.remove(lhs);
|
||||
break;
|
||||
}
|
||||
print(TREE_CODE(rhs));
|
||||
throw new Error("ni");
|
||||
return;
|
||||
}
|
||||
|
||||
// Nothing special -- delegate
|
||||
this.zeroNonzero.processAssign(isn, state);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (TREE_CODE(lhs)) {
|
||||
case INDIRECT_REF:
|
||||
// Writing to an outparam. We want to try to figure out if we're writing NULL.
|
||||
// Writing to an outparam. We want to try to figure out if we're
|
||||
// writing NULL.
|
||||
let e = TREE_OPERAND(lhs, 0);
|
||||
if (this.outparams.has(e)) {
|
||||
if (expr_literal_int(rhs) == 0) {
|
||||
|
@ -509,9 +386,9 @@ OutparamCheck.prototype.processAssign = function(isn, state) {
|
|||
OutparamCheck.prototype.processTest = function(lhs, call, val, blame, state) {
|
||||
let arg = call_arg(call, 0);
|
||||
if (DECL_P(arg)) {
|
||||
state.predicate(lhs, val, arg, blame);
|
||||
this.zeroNonzero.predicate(state, lhs, val, arg, blame);
|
||||
} else {
|
||||
state.assignValue(lhs, av.BOTTOM, blame);
|
||||
state.assignValue(lhs, ESP.TOP, blame);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -650,14 +527,13 @@ OutparamCheck.prototype.checkSubstate = function(isvoid, fndecl, ss) {
|
|||
} else {
|
||||
let [succ, fail] = ret_coding(fndecl);
|
||||
let rv = ss.get(this.retvar);
|
||||
switch (rv) {
|
||||
case succ:
|
||||
// We want to check if the abstract value of the rv is entirely
|
||||
// contained in the success or failure condition.
|
||||
if (av.meet(rv, succ) == rv) {
|
||||
this.checkSubstateSuccess(ss);
|
||||
break;
|
||||
case fail:
|
||||
} else if (av.meet(rv, fail) == rv) {
|
||||
this.checkSubstateFailure(ss);
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
// This condition indicates a bug in outparams.js. We'll just
|
||||
// warn so we don't break static analysis builds.
|
||||
warning("Outparams checker cannot determine rv success/failure",
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
#define NS_ABORT_IF_FALSE(_expr, _msg) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (!(_expr)) { \
|
||||
NS_DebugBreak(NS_DEBUG_ASSERTION, _msg, #_expr, __FILE__, __LINE__); \
|
||||
NS_DebugBreak(NS_DEBUG_ABORT, _msg, #_expr, __FILE__, __LINE__); \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче