mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 20:05:49 +00:00
Bug 1020244 - Ability to insert AnonymousContent nodes in the canvasFrame via a chrome-only Document API; r=smaug; r=roc; r=ehsan
This commit is contained in:
parent
f510bc6ce1
commit
159aa067df
@ -33,6 +33,12 @@ AnonymousContent::GetContentNode()
|
||||
return mContentNode;
|
||||
}
|
||||
|
||||
void
|
||||
AnonymousContent::SetContentNode(Element* aContentNode)
|
||||
{
|
||||
mContentNode = aContentNode;
|
||||
}
|
||||
|
||||
void
|
||||
AnonymousContent::SetTextContentForElement(const nsAString& aElementId,
|
||||
const nsAString& aText,
|
||||
|
@ -26,6 +26,7 @@ public:
|
||||
|
||||
explicit AnonymousContent(Element* aContentNode);
|
||||
nsCOMPtr<Element> GetContentNode();
|
||||
void SetContentNode(Element* aContentNode);
|
||||
JSObject* WrapObject(JSContext* aCx);
|
||||
|
||||
// WebIDL methods
|
||||
|
@ -68,6 +68,7 @@
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIServiceWorkerManager.h"
|
||||
|
||||
#include "nsCanvasFrame.h"
|
||||
#include "nsContentCID.h"
|
||||
#include "nsError.h"
|
||||
#include "nsPresShell.h"
|
||||
@ -182,6 +183,7 @@
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
#include "nsIAppsService.h"
|
||||
#include "mozilla/dom/AnonymousContent.h"
|
||||
#include "mozilla/dom/AnimationTimeline.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
@ -1986,6 +1988,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRegistry)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents)
|
||||
|
||||
// Traverse all our nsCOMArrays.
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
|
||||
@ -5138,6 +5141,78 @@ nsDocument::StyleRuleRemoved(nsIStyleSheet* aSheet,
|
||||
|
||||
#undef DO_STYLESHEET_NOTIFICATION
|
||||
|
||||
already_AddRefed<AnonymousContent>
|
||||
nsIDocument::InsertAnonymousContent(Element& aElement, ErrorResult& aRv)
|
||||
{
|
||||
nsIPresShell* shell = GetShell();
|
||||
if (!shell || !shell->GetCanvasFrame()) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<Element> container = shell->GetCanvasFrame()
|
||||
->GetCustomContentContainer();
|
||||
if (!container) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Clone the node to avoid returning a direct reference
|
||||
nsCOMPtr<nsINode> clonedElement = aElement.CloneNode(true, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Insert the element into the container
|
||||
nsresult rv;
|
||||
rv = container->AppendChildTo(clonedElement->AsContent(), true);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<AnonymousContent> anonymousContent =
|
||||
new AnonymousContent(clonedElement->AsElement());
|
||||
mAnonymousContents.AppendElement(anonymousContent);
|
||||
|
||||
return anonymousContent.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::RemoveAnonymousContent(AnonymousContent& aContent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsIPresShell* shell = GetShell();
|
||||
if (!shell) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<Element> container = shell->GetCanvasFrame()
|
||||
->GetCustomContentContainer();
|
||||
if (!container) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate over know customContents to get and remove the right one
|
||||
for (int32_t i = mAnonymousContents.Length() - 1; i >= 0; --i) {
|
||||
if (mAnonymousContents[i] == &aContent) {
|
||||
// Get the node from the customContent
|
||||
nsCOMPtr<Element> node = aContent.GetContentNode();
|
||||
|
||||
// Remove the entry in mAnonymousContents
|
||||
mAnonymousContents.RemoveElementAt(i);
|
||||
|
||||
// Remove the node from its container
|
||||
container->RemoveChild(*node, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// nsIDOMDocument interface
|
||||
|
@ -92,6 +92,7 @@ class ImageLoader;
|
||||
|
||||
namespace dom {
|
||||
class AnimationTimeline;
|
||||
class AnonymousContent;
|
||||
class Attr;
|
||||
class BoxObject;
|
||||
class CDATASection;
|
||||
@ -715,6 +716,15 @@ public:
|
||||
return mDidDocumentOpen;
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::AnonymousContent>
|
||||
InsertAnonymousContent(mozilla::dom::Element& aElement,
|
||||
mozilla::ErrorResult& aError);
|
||||
void RemoveAnonymousContent(mozilla::dom::AnonymousContent& aContent,
|
||||
mozilla::ErrorResult& aError);
|
||||
nsTArray<nsRefPtr<mozilla::dom::AnonymousContent>>& GetAnonymousContents() {
|
||||
return mAnonymousContents;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Element *GetRootElementInternal() const = 0;
|
||||
|
||||
@ -2747,6 +2757,8 @@ protected:
|
||||
|
||||
nsRefPtr<mozilla::dom::XPathEvaluator> mXPathEvaluator;
|
||||
|
||||
nsTArray<nsRefPtr<mozilla::dom::AnonymousContent>> mAnonymousContents;
|
||||
|
||||
uint32_t mBlockDOMContentLoaded;
|
||||
bool mDidFireDOMContentLoaded:1;
|
||||
};
|
||||
|
@ -355,6 +355,30 @@ partial interface Document {
|
||||
[ChromeOnly] readonly attribute boolean isSrcdocDocument;
|
||||
};
|
||||
|
||||
/**
|
||||
* Chrome document anonymous content management.
|
||||
* This is a Chrome-only API that allows inserting fixed positioned anonymous
|
||||
* content on top of the current page displayed in the document.
|
||||
* The supplied content is cloned and inserted into the document's CanvasFrame.
|
||||
* Note that this only works for HTML documents.
|
||||
*/
|
||||
partial interface Document {
|
||||
/**
|
||||
* Deep-clones the provided element and inserts it into the CanvasFrame.
|
||||
* Returns an AnonymousContent instance that can be used to manipulate the
|
||||
* inserted element.
|
||||
*/
|
||||
[ChromeOnly, NewObject, Throws]
|
||||
AnonymousContent insertAnonymousContent(Element aElement);
|
||||
|
||||
/**
|
||||
* Removes the element inserted into the CanvasFrame given an AnonymousContent
|
||||
* instance.
|
||||
*/
|
||||
[ChromeOnly, Throws]
|
||||
void removeAnonymousContent(AnonymousContent aContent);
|
||||
};
|
||||
|
||||
Document implements XPathEvaluator;
|
||||
Document implements GlobalEventHandlers;
|
||||
Document implements TouchEventHandlers;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "nsFrameManager.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "mozilla/dom/AnonymousContent.h"
|
||||
// for touchcaret
|
||||
#include "nsContentList.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
@ -35,6 +36,7 @@
|
||||
//#define DEBUG_CANVAS_FOCUS
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::layout;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
@ -63,7 +65,7 @@ nsCanvasFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
||||
ErrorResult er;
|
||||
// We won't create touch caret element if preference is not enabled.
|
||||
if (PresShell::TouchCaretPrefEnabled()) {
|
||||
nsRefPtr<dom::NodeInfo> nodeInfo;
|
||||
nsRefPtr<NodeInfo> nodeInfo;
|
||||
|
||||
// Create and append touch caret frame.
|
||||
nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::div, nullptr,
|
||||
@ -72,7 +74,7 @@ nsCanvasFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
||||
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = NS_NewHTMLElement(getter_AddRefs(mTouchCaretElement), nodeInfo.forget(),
|
||||
mozilla::dom::NOT_FROM_PARSER);
|
||||
NOT_FROM_PARSER);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
aElements.AppendElement(mTouchCaretElement);
|
||||
|
||||
@ -103,6 +105,23 @@ nsCanvasFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Create the custom content container.
|
||||
mCustomContentContainer = doc->CreateHTMLElement(nsGkAtoms::div);
|
||||
aElements.AppendElement(mCustomContentContainer);
|
||||
|
||||
// XXX add :moz-native-anonymous or will that be automatically set?
|
||||
rv = mCustomContentContainer->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
|
||||
NS_LITERAL_STRING("moz-custom-content-container"),
|
||||
true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Append all existing AnonymousContent nodes stored at document level if any.
|
||||
int32_t anonymousContentCount = doc->GetAnonymousContents().Length();
|
||||
for (int32_t i = 0; i < anonymousContentCount; ++i) {
|
||||
nsCOMPtr<Element> node = doc->GetAnonymousContents()[i]->GetContentNode();
|
||||
mCustomContentContainer->AppendChildTo(node->AsContent(), true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -120,6 +139,8 @@ nsCanvasFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements, uint32
|
||||
if (mSelectionCaretsEndElement) {
|
||||
aElements.AppendElement(mSelectionCaretsEndElement);
|
||||
}
|
||||
|
||||
aElements.AppendElement(mCustomContentContainer);
|
||||
}
|
||||
|
||||
void
|
||||
@ -134,6 +155,22 @@ nsCanvasFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
nsContentUtils::DestroyAnonymousContent(&mTouchCaretElement);
|
||||
nsContentUtils::DestroyAnonymousContent(&mSelectionCaretsStartElement);
|
||||
nsContentUtils::DestroyAnonymousContent(&mSelectionCaretsEndElement);
|
||||
|
||||
// Elements inserted in the custom content container have the same lifetime as
|
||||
// the document, so before destroying the container, make sure to keep a clone
|
||||
// of each of them at document level so they can be re-appended on reframe.
|
||||
if (mCustomContentContainer) {
|
||||
nsCOMPtr<nsIDocument> doc = mContent->OwnerDoc();
|
||||
ErrorResult rv;
|
||||
|
||||
for (int32_t i = doc->GetAnonymousContents().Length() - 1; i >= 0; --i) {
|
||||
AnonymousContent* content = doc->GetAnonymousContents()[i];
|
||||
nsCOMPtr<nsINode> clonedElement = content->GetContentNode()->CloneNode(true, rv);
|
||||
content->SetContentNode(clonedElement->AsElement());
|
||||
}
|
||||
}
|
||||
nsContentUtils::DestroyAnonymousContent(&mCustomContentContainer);
|
||||
|
||||
nsContainerFrame::DestroyFrom(aDestructRoot);
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,11 @@ public:
|
||||
return mSelectionCaretsEndElement;
|
||||
}
|
||||
|
||||
mozilla::dom::Element* GetCustomContentContainer() const
|
||||
{
|
||||
return mCustomContentContainer;
|
||||
}
|
||||
|
||||
/** SetHasFocus tells the CanvasFrame to draw with focus ring
|
||||
* @param aHasFocus true to show focus ring, false to hide it
|
||||
*/
|
||||
@ -138,6 +143,7 @@ protected:
|
||||
nsCOMPtr<mozilla::dom::Element> mTouchCaretElement;
|
||||
nsCOMPtr<mozilla::dom::Element> mSelectionCaretsStartElement;
|
||||
nsCOMPtr<mozilla::dom::Element> mSelectionCaretsEndElement;
|
||||
nsCOMPtr<mozilla::dom::Element> mCustomContentContainer;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -6914,8 +6914,12 @@ nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
|
||||
frameTraversal->Prev();
|
||||
|
||||
traversedFrame = frameTraversal->CurrentItem();
|
||||
if (!traversedFrame)
|
||||
|
||||
// Skip anonymous elements
|
||||
if (!traversedFrame ||
|
||||
traversedFrame->GetContent()->IsRootOfNativeAnonymousSubtree())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
traversedFrame->IsSelectable(&selectable, nullptr);
|
||||
} // while (!selectable)
|
||||
|
||||
|
@ -2410,7 +2410,7 @@ public:
|
||||
virtual nsresult PeekOffset(nsPeekOffsetStruct *aPos);
|
||||
|
||||
/**
|
||||
* called to find the previous/next selectable leaf frame.
|
||||
* called to find the previous/next non-anonymous selectable leaf frame.
|
||||
* @param aDirection [in] the direction to move in (eDirPrevious or eDirNext)
|
||||
* @param aVisual [in] whether bidi caret behavior is visual (true) or logical (false)
|
||||
* @param aJumpLines [in] whether to allow jumping across line boundaries
|
||||
|
@ -390,3 +390,17 @@ div:-moz-native-anonymous.moz-selectioncaret-right.hidden {
|
||||
margin: 0px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/* Custom content container in the CanvasFrame, fixed positioned on top of
|
||||
everything else, not reacting to pointer events. */
|
||||
div:-moz-native-anonymous.moz-custom-content-container {
|
||||
pointer-events: none;
|
||||
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
z-index: 2147483648;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user