NS_IMETHODIMP
XULContentSinkImpl::HandleStartElement(const PRUnichar *aName,
const PRUnichar **aAtts,
uint32_t aAttsCount,
int32_t aIndex,
uint32_t aLineNumber)
{
// XXX Hopefully the parser will flag this before we get here. If
// we're in the epilog, there should be no new elements
NS_PRECONDITION(mState != eInEpilog, "tag in XUL doc epilog");
NS_PRECONDITION(aIndex >= -1, "Bogus aIndex");
NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
// Adjust aAttsCount so it's the actual number of attributes
aAttsCount /= 2;
if (mState == eInEpilog)
return NS_ERROR_UNEXPECTED;
if (mState != eInScript) {
FlushText();
}
int32_t nameSpaceID;
nsCOMPtr<nsIAtom> prefix, localName;
nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
getter_AddRefs(localName), &nameSpaceID);
nsCOMPtr<nsINodeInfo> nodeInfo;
nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
nsIDOMNode::ELEMENT_NODE);
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = NS_OK;
switch (mState) {
case eInProlog:
// We're the root document element
rv = OpenRoot(aAtts, aAttsCount, nodeInfo);
break;
case eInDocumentElement:
rv = OpenTag(aAtts, aAttsCount, aLineNumber, nodeInfo);
break;
case eInEpilog:
case eInScript:
PR_LOG(gLog, PR_LOG_WARNING,
("xul: warning: unexpected tags in epilog at line %d",
aLineNumber));
rv = NS_ERROR_UNEXPECTED; // XXX
break;
}
// Set the ID attribute atom on the node info object for this node
if (aIndex != -1 && NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]);
if (IDAttr) {
nodeInfo->SetIDAttributeAtom(IDAttr);
}
}
return rv;
}
NS_IMETHODIMP nsViewManager::InsertChild(nsIView *aParent, nsIView *aChild, nsIView *aSibling,
bool aAfter)
{
nsView* parent = static_cast<nsView*>(aParent);
nsView* child = static_cast<nsView*>(aChild);
nsView* sibling = static_cast<nsView*>(aSibling);
NS_PRECONDITION(nullptr != parent, "null ptr");
NS_PRECONDITION(nullptr != child, "null ptr");
NS_ASSERTION(sibling == nullptr || sibling->GetParent() == parent,
"tried to insert view with invalid sibling");
NS_ASSERTION(!IsViewInserted(child), "tried to insert an already-inserted view");
if ((nullptr != parent) && (nullptr != child))
{
// if aAfter is set, we will insert the child after 'prev' (i.e. after 'kid' in document
// order, otherwise after 'kid' (i.e. before 'kid' in document order).
#if 1
if (nullptr == aSibling) {
if (aAfter) {
// insert at end of document order, i.e., before first view
// this is the common case, by far
parent->InsertChild(child, nullptr);
ReparentWidgets(child, parent);
} else {
// insert at beginning of document order, i.e., after last view
nsView *kid = parent->GetFirstChild();
nsView *prev = nullptr;
while (kid) {
prev = kid;
kid = kid->GetNextSibling();
}
// prev is last view or null if there are no children
parent->InsertChild(child, prev);
ReparentWidgets(child, parent);
}
} else {
nsView *kid = parent->GetFirstChild();
nsView *prev = nullptr;
while (kid && sibling != kid) {
//get the next sibling view
prev = kid;
kid = kid->GetNextSibling();
}
NS_ASSERTION(kid != nullptr,
"couldn't find sibling in child list");
if (aAfter) {
// insert after 'kid' in document order, i.e. before in view order
parent->InsertChild(child, prev);
ReparentWidgets(child, parent);
} else {
// insert before 'kid' in document order, i.e. after in view order
parent->InsertChild(child, kid);
ReparentWidgets(child, parent);
}
}
#else // don't keep consistent document order, but order things by z-index instead
// essentially we're emulating the old InsertChild(parent, child, zindex)
PRInt32 zIndex = child->GetZIndex();
while (nullptr != kid)
{
PRInt32 idx = kid->GetZIndex();
if (CompareZIndex(zIndex, child->IsTopMost(), child->GetZIndexIsAuto(),
idx, kid->IsTopMost(), kid->GetZIndexIsAuto()) >= 0)
break;
prev = kid;
kid = kid->GetNextSibling();
}
parent->InsertChild(child, prev);
ReparentWidgets(child, parent);
#endif
// if the parent view is marked as "floating", make the newly added view float as well.
if (parent->GetFloating())
child->SetFloating(true);
//and mark this area as dirty if the view is visible...
if (nsViewVisibility_kHide != child->GetVisibility())
child->GetViewManager()->InvalidateView(child);
}
return NS_OK;
}
nsresult
nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
{
NS_PRECONDITION(IsCompiled(), "Can't execute uncompiled method");
if (!mJSMethodObject) {
// Nothing to do here
return NS_OK;
}
// Get the script context the same way
// nsXBLProtoImpl::InstallImplementation does.
nsIDocument* document = aBoundElement->GetOwnerDoc();
if (!document) {
return NS_OK;
}
nsIScriptGlobalObject* global = document->GetScriptGlobalObject();
if (!global) {
return NS_OK;
}
nsCOMPtr<nsIScriptContext> context = global->GetContext();
if (!context) {
return NS_OK;
}
JSContext* cx = (JSContext*) context->GetNativeContext();
JSObject* globalObject = global->GetGlobalJSObject();
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
jsval v;
nsresult rv =
nsContentUtils::WrapNative(cx, globalObject, aBoundElement, &v,
getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);
JSObject* thisObject = JSVAL_TO_OBJECT(v);
JSAutoRequest ar(cx);
JSAutoEnterCompartment ac;
if (!ac.enter(cx, thisObject))
return NS_ERROR_UNEXPECTED;
// Clone the function object, using thisObject as the parent so "this" is in
// the scope chain of the resulting function (for backwards compat to the
// days when this was an event handler).
JSObject* method = ::JS_CloneFunctionObject(cx, mJSMethodObject, thisObject);
if (!method)
return NS_ERROR_OUT_OF_MEMORY;
// Now call the method
// Use nsCxPusher to make sure we call ScriptEvaluated when we're done.
nsCxPusher pusher;
NS_ENSURE_STATE(pusher.Push(aBoundElement));
// Check whether it's OK to call the method.
rv = nsContentUtils::GetSecurityManager()->CheckFunctionAccess(cx, method,
thisObject);
JSBool ok = JS_TRUE;
if (NS_SUCCEEDED(rv)) {
jsval retval;
ok = ::JS_CallFunctionValue(cx, thisObject, OBJECT_TO_JSVAL(method),
0 /* argc */, nsnull /* argv */, &retval);
}
if (!ok) {
// If a constructor or destructor threw an exception, it doesn't stop
// anything else. We just report it. Note that we need to set aside the
// frame chain here, since the constructor invocation is not related to
// whatever is on the stack right now, really.
JSBool saved = JS_SaveFrameChain(cx);
JS_ReportPendingException(cx);
if (saved)
JS_RestoreFrameChain(cx);
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString& aClassStr,
JSObject* aClassObject)
{
NS_PRECONDITION(!IsCompiled(),
"Trying to compile an already-compiled method");
NS_PRECONDITION(aClassObject,
"Must have class object to compile");
nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
// No parameters or body was supplied, so don't install method.
if (!uncompiledMethod) {
// Early return after which we consider ourselves compiled.
mJSMethodObject = nullptr;
return NS_OK;
}
// Don't install method if no name was supplied.
if (!mName) {
delete uncompiledMethod;
// Early return after which we consider ourselves compiled.
mJSMethodObject = nullptr;
return NS_OK;
}
// We have a method.
// Allocate an array for our arguments.
int32_t paramCount = uncompiledMethod->GetParameterCount();
char** args = nullptr;
if (paramCount > 0) {
args = new char*[paramCount];
if (!args)
return NS_ERROR_OUT_OF_MEMORY;
// Add our parameters to our args array.
int32_t argPos = 0;
for (nsXBLParameter* curr = uncompiledMethod->mParameters;
curr;
curr = curr->mNext) {
args[argPos] = curr->mName;
argPos++;
}
}
// Get the body
nsDependentString body;
PRUnichar *bodyText = uncompiledMethod->mBodyText.GetText();
if (bodyText)
body.Rebind(bodyText);
// Now that we have a body and args, compile the function
// and then define it.
NS_ConvertUTF16toUTF8 cname(mName);
nsAutoCString functionUri(aClassStr);
int32_t hash = functionUri.RFindChar('#');
if (hash != kNotFound) {
functionUri.Truncate(hash);
}
JSObject* methodObject = nullptr;
JSContext* cx = aContext->GetNativeContext();
JSAutoRequest ar(cx);
JSAutoCompartment ac(cx, aClassObject);
JS::CompileOptions options(cx);
options.setFileAndLine(functionUri.get(),
uncompiledMethod->mBodyText.GetLineNumber())
.setVersion(JSVERSION_LATEST)
.setUserBit(true); // Flag us as XBL
js::RootedObject rootedNull(cx, nullptr); // See bug 781070.
nsresult rv = nsJSUtils::CompileFunction(cx, rootedNull, options, cname,
paramCount,
const_cast<const char**>(args),
body, &methodObject);
// Destroy our uncompiled method and delete our arg list.
delete uncompiledMethod;
delete [] args;
if (NS_FAILED(rv)) {
SetUncompiledMethod(nullptr);
return rv;
}
mJSMethodObject = methodObject;
return NS_OK;
}
nsresult
nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCString& aClassStr,
void* aClassObject)
{
NS_PRECONDITION(!mIsCompiled,
"Trying to compile an already-compiled property");
NS_PRECONDITION(aClassObject,
"Must have class object to compile");
if (!mName)
return NS_ERROR_FAILURE; // Without a valid name, we can't install the member.
// We have a property.
nsresult rv = NS_OK;
nsCAutoString functionUri;
if (mGetterText || mSetterText) {
functionUri = aClassStr;
PRInt32 hash = functionUri.RFindChar('#');
if (hash != kNotFound) {
functionUri.Truncate(hash);
}
}
PRBool deletedGetter = PR_FALSE;
if (mGetterText && mGetterText->GetText()) {
nsDependentString getter(mGetterText->GetText());
if (!getter.IsEmpty()) {
// Compile into a temp object so we don't wipe out mGetterText
JSObject* getterObject = nsnull;
rv = aContext->CompileFunction(aClassObject,
NS_LITERAL_CSTRING("get_") +
NS_ConvertUTF16toUTF8(mName),
0,
nsnull,
getter,
functionUri.get(),
mGetterText->GetLineNumber(),
JSVERSION_LATEST,
PR_TRUE,
(void **) &getterObject);
// Make sure we free mGetterText here before setting mJSGetterObject, since
// that'll overwrite mGetterText
delete mGetterText;
deletedGetter = PR_TRUE;
mJSGetterObject = getterObject;
if (mJSGetterObject && NS_SUCCEEDED(rv)) {
mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
}
if (NS_FAILED(rv)) {
mJSGetterObject = nsnull;
mJSAttributes &= ~JSPROP_GETTER;
/*chaining to return failure*/
}
}
} // if getter is not empty
if (!deletedGetter) { // Empty getter
delete mGetterText;
mJSGetterObject = nsnull;
}
if (NS_FAILED(rv)) {
// We failed to compile our getter. So either we've set it to null, or
// it's still set to the text object. In either case, it's safe to return
// the error here, since then we'll be cleaned up as uncompiled and that
// will be ok. Going on and compiling the setter and _then_ returning an
// error, on the other hand, will try to clean up a compiled setter as
// uncompiled and crash.
return rv;
}
PRBool deletedSetter = PR_FALSE;
if (mSetterText && mSetterText->GetText()) {
nsDependentString setter(mSetterText->GetText());
if (!setter.IsEmpty()) {
// Compile into a temp object so we don't wipe out mSetterText
JSObject* setterObject = nsnull;
rv = aContext->CompileFunction(aClassObject,
NS_LITERAL_CSTRING("set_") +
NS_ConvertUTF16toUTF8(mName),
1,
gPropertyArgs,
setter,
functionUri.get(),
mSetterText->GetLineNumber(),
JSVERSION_LATEST,
PR_TRUE,
(void **) &setterObject);
// Make sure we free mSetterText here before setting mJSGetterObject, since
// that'll overwrite mSetterText
delete mSetterText;
deletedSetter = PR_TRUE;
mJSSetterObject = setterObject;
if (mJSSetterObject && NS_SUCCEEDED(rv)) {
mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
//.........这里部分代码省略.........
//
// Called by nsCSSFrameConstructor when listitem content is removed.
//
void
nsListBoxBodyFrame::OnContentRemoved(nsPresContext* aPresContext,
nsIContent* aContainer,
nsIFrame* aChildFrame,
nsIContent* aOldNextSibling)
{
NS_ASSERTION(!aChildFrame || aChildFrame->GetParent() == this,
"Removing frame that's not our child... Not good");
if (mRowCount >= 0)
--mRowCount;
if (aContainer) {
if (!aChildFrame) {
// The row we are removing is out of view, so we need to try to
// determine the index of its next sibling.
int32_t siblingIndex = -1;
if (aOldNextSibling) {
nsCOMPtr<nsIContent> nextSiblingContent;
GetListItemNextSibling(aOldNextSibling,
getter_AddRefs(nextSiblingContent),
siblingIndex);
}
// if the row being removed is off-screen and above the top frame, we need to
// adjust our top index and tell the scrollbar to shift up one row.
if (siblingIndex >= 0 && siblingIndex-1 < mCurrentIndex) {
NS_PRECONDITION(mCurrentIndex > 0, "mCurrentIndex > 0");
--mCurrentIndex;
mYPosition = mCurrentIndex*mRowHeight;
VerticalScroll(mYPosition);
}
} else if (mCurrentIndex > 0) {
// At this point, we know we have a scrollbar, and we need to know
// if we are scrolled to the last row. In this case, the behavior
// of the scrollbar is to stay locked to the bottom. Since we are
// removing visible content, the first visible row will have to move
// down by one, and we will have to insert a new frame at the top.
// if the last content node has a frame, we are scrolled to the bottom
ChildIterator iter, last;
ChildIterator::Init(mContent, &iter, &last);
if (iter != last) {
iter = last;
--iter;
nsIContent *lastChild = *iter;
nsIFrame* lastChildFrame = lastChild->GetPrimaryFrame();
if (lastChildFrame) {
mTopFrame = nullptr;
mRowsToPrepend = 1;
--mCurrentIndex;
mYPosition = mCurrentIndex*mRowHeight;
VerticalScroll(mYPosition);
}
}
}
}
// if we're removing the top row, the new top row is the next row
if (mTopFrame && mTopFrame == aChildFrame)
mTopFrame = mTopFrame->GetNextSibling();
// Go ahead and delete the frame.
nsBoxLayoutState state(aPresContext);
if (aChildFrame) {
RemoveChildFrame(state, aChildFrame);
}
PresContext()->PresShell()->
FrameNeedsReflow(this, nsIPresShell::eTreeChange,
NS_FRAME_HAS_DIRTY_CHILDREN);
}
nsresult
nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString& aClassStr,
void* aClassObject)
{
NS_TIME_FUNCTION_MIN(5);
NS_PRECONDITION(!IsCompiled(),
"Trying to compile an already-compiled method");
NS_PRECONDITION(aClassObject,
"Must have class object to compile");
nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
// No parameters or body was supplied, so don't install method.
if (!uncompiledMethod) {
// Early return after which we consider ourselves compiled.
mJSMethodObject = nsnull;
return NS_OK;
}
// Don't install method if no name was supplied.
if (!mName) {
delete uncompiledMethod;
// Early return after which we consider ourselves compiled.
mJSMethodObject = nsnull;
return NS_OK;
}
// We have a method.
// Allocate an array for our arguments.
PRInt32 paramCount = uncompiledMethod->GetParameterCount();
char** args = nsnull;
if (paramCount > 0) {
args = new char*[paramCount];
if (!args)
return NS_ERROR_OUT_OF_MEMORY;
// Add our parameters to our args array.
PRInt32 argPos = 0;
for (nsXBLParameter* curr = uncompiledMethod->mParameters;
curr;
curr = curr->mNext) {
args[argPos] = curr->mName;
argPos++;
}
}
// Get the body
nsDependentString body;
PRUnichar *bodyText = uncompiledMethod->mBodyText.GetText();
if (bodyText)
body.Rebind(bodyText);
// Now that we have a body and args, compile the function
// and then define it.
NS_ConvertUTF16toUTF8 cname(mName);
nsCAutoString functionUri(aClassStr);
PRInt32 hash = functionUri.RFindChar('#');
if (hash != kNotFound) {
functionUri.Truncate(hash);
}
JSObject* methodObject = nsnull;
nsresult rv = aContext->CompileFunction(aClassObject,
cname,
paramCount,
(const char**)args,
body,
functionUri.get(),
uncompiledMethod->mBodyText.GetLineNumber(),
JSVERSION_LATEST,
PR_TRUE,
(void **) &methodObject);
// Destroy our uncompiled method and delete our arg list.
delete uncompiledMethod;
delete [] args;
if (NS_FAILED(rv)) {
SetUncompiledMethod(nsnull);
return rv;
}
mJSMethodObject = methodObject;
return NS_OK;
}
// XXXldb This behavior doesn't quite fit with CSS1 and CSS2 --
// technically we're supposed let the current line flow around the
// float as well unless it won't fit next to what we already have.
// But nobody else implements it that way...
PRBool
nsBlockReflowState::AddFloat(nsLineLayout& aLineLayout,
nsPlaceholderFrame* aPlaceholder,
PRBool aInitialReflow,
nsReflowStatus& aReflowStatus)
{
NS_PRECONDITION(mBlock->end_lines() != mCurrentLine, "null ptr");
aReflowStatus = NS_FRAME_COMPLETE;
// Allocate a nsFloatCache for the float
nsFloatCache* fc = mFloatCacheFreeList.Alloc();
fc->mPlaceholder = aPlaceholder;
PRBool placed;
// Now place the float immediately if possible. Otherwise stash it
// away in mPendingFloats and place it later.
if (aLineLayout.CanPlaceFloatNow()) {
// Because we are in the middle of reflowing a placeholder frame
// within a line (and possibly nested in an inline frame or two
// that's a child of our block) we need to restore the space
// manager's translation to the space that the block resides in
// before placing the float.
nscoord ox, oy;
mSpaceManager->GetTranslation(ox, oy);
nscoord dx = ox - mSpaceManagerX;
nscoord dy = oy - mSpaceManagerY;
mSpaceManager->Translate(-dx, -dy);
// And then place it
PRBool isLeftFloat;
// force it to fit if we're at the top of the block and we can't
// break before this
PRBool forceFit = IsAdjacentWithTop() && !aLineLayout.LineIsBreakable();
placed = FlowAndPlaceFloat(fc, &isLeftFloat, aReflowStatus, forceFit);
NS_ASSERTION(placed || !forceFit,
"If we asked for force-fit, it should have been placed");
if (forceFit || (placed && !NS_FRAME_IS_TRUNCATED(aReflowStatus))) {
// Pass on updated available space to the current inline reflow engine
GetAvailableSpace(mY, forceFit);
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
mAvailSpaceRect.width,
mAvailSpaceRect.height,
isLeftFloat,
aPlaceholder->GetOutOfFlowFrame());
// Record this float in the current-line list
mCurrentLineFloats.Append(fc);
// If we can't break here, hide the fact that it's truncated
// XXX We can probably do this more cleanly
aReflowStatus &= ~NS_FRAME_TRUNCATED;
}
else {
if (IsAdjacentWithTop()) {
// Pushing the line to the next page won't give us any more space;
// therefore, we break.
NS_ASSERTION(aLineLayout.LineIsBreakable(),
"We can't get here unless forceFit is false");
aReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
} else {
// Make sure we propagate the truncated status; this signals the
// block to push the line to the next page.
aReflowStatus |= NS_FRAME_TRUNCATED;
}
delete fc;
}
// Restore coordinate system
mSpaceManager->Translate(dx, dy);
}
else {
// Always claim to be placed; we don't know whether we fit yet, so we
// deal with this in PlaceBelowCurrentLineFloats
placed = PR_TRUE;
// This float will be placed after the line is done (it is a
// below-current-line float).
mBelowCurrentLineFloats.Append(fc);
if (aPlaceholder->GetNextInFlow()) {
// If the float might not be complete, mark it incomplete now to
// prevent its next-in-flow placeholders being torn down. We will destroy any
// placeholders later if PlaceBelowCurrentLineFloats finds the
// float is complete.
// Note that we could have unconstrained height and yet have
// a next-in-flow placeholder --- for example columns can switch
// from constrained height to unconstrained height.
if (aPlaceholder->GetSplittableType() != NS_FRAME_NOT_SPLITTABLE) {
aReflowStatus = NS_FRAME_NOT_COMPLETE;
}
}
}
return placed;
}
请发表评论