1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 /**
8  * A fake content node class so that the image frame for
9  *   content: url(foo);
10  * in CSS can have an nsIImageLoadingContent but use an
11  * imgIRequest that's already been loaded from the style system.
12  */
13 
14 #include "nsContentCreatorFunctions.h"
15 #include "nsXMLElement.h"
16 #include "nsImageLoadingContent.h"
17 #include "imgIRequest.h"
18 #include "mozilla/BasicEvents.h"
19 #include "mozilla/EventDispatcher.h"
20 #include "mozilla/EventStates.h"
21 
22 using namespace mozilla;
23 
24 class nsGenConImageContent final : public nsXMLElement,
25                                    public nsImageLoadingContent
26 {
27 public:
nsGenConImageContent(already_AddRefed<mozilla::dom::NodeInfo> & aNodeInfo)28   explicit nsGenConImageContent(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
29     : nsXMLElement(aNodeInfo)
30   {
31     // nsImageLoadingContent starts out broken, so we start out
32     // suppressed to match it.
33     AddStatesSilently(NS_EVENT_STATE_SUPPRESSED);
34   }
35 
Init(imgRequestProxy * aImageRequest)36   nsresult Init(imgRequestProxy* aImageRequest)
37   {
38     // No need to notify, since we have no frame.
39     return UseAsPrimaryRequest(aImageRequest, false, eImageLoadType_Normal);
40   }
41 
42   // nsIContent overrides
43   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
44                               nsIContent* aBindingParent,
45                               bool aCompileEventHandlers) override;
46   virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
47   virtual EventStates IntrinsicState() const override;
48 
PreHandleEvent(EventChainPreVisitor & aVisitor)49   virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override
50   {
51     MOZ_ASSERT(IsInNativeAnonymousSubtree());
52     if (aVisitor.mEvent->mMessage == eLoad ||
53         aVisitor.mEvent->mMessage == eLoadError) {
54       // Don't propagate the events to the parent.
55       return NS_OK;
56     }
57     return nsXMLElement::PreHandleEvent(aVisitor);
58   }
59 
60 private:
61   virtual ~nsGenConImageContent();
62 
63 public:
64   NS_DECL_ISUPPORTS_INHERITED
65 };
66 
NS_IMPL_ISUPPORTS_INHERITED(nsGenConImageContent,nsXMLElement,nsIImageLoadingContent,imgINotificationObserver,imgIOnloadBlocker)67 NS_IMPL_ISUPPORTS_INHERITED(nsGenConImageContent,
68                             nsXMLElement,
69                             nsIImageLoadingContent,
70                             imgINotificationObserver,
71                             imgIOnloadBlocker)
72 
73 nsresult
74 NS_NewGenConImageContent(nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
75                          imgRequestProxy* aImageRequest)
76 {
77   NS_PRECONDITION(aImageRequest, "Must have request!");
78   nsGenConImageContent *it = new nsGenConImageContent(aNodeInfo);
79   NS_ADDREF(*aResult = it);
80   nsresult rv = it->Init(aImageRequest);
81   if (NS_FAILED(rv))
82     NS_RELEASE(*aResult);
83   return rv;
84 }
85 
~nsGenConImageContent()86 nsGenConImageContent::~nsGenConImageContent()
87 {
88   DestroyImageLoadingContent();
89 }
90 
91 nsresult
BindToTree(nsIDocument * aDocument,nsIContent * aParent,nsIContent * aBindingParent,bool aCompileEventHandlers)92 nsGenConImageContent::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
93                                  nsIContent* aBindingParent,
94                                  bool aCompileEventHandlers)
95 {
96   nsresult rv;
97   rv = nsXMLElement::BindToTree(aDocument, aParent, aBindingParent,
98                                 aCompileEventHandlers);
99   NS_ENSURE_SUCCESS(rv, rv);
100 
101   nsImageLoadingContent::BindToTree(aDocument, aParent, aBindingParent,
102                                     aCompileEventHandlers);
103   return NS_OK;
104 }
105 
106 void
UnbindFromTree(bool aDeep,bool aNullParent)107 nsGenConImageContent::UnbindFromTree(bool aDeep, bool aNullParent)
108 {
109   nsImageLoadingContent::UnbindFromTree(aDeep, aNullParent);
110   nsXMLElement::UnbindFromTree(aDeep, aNullParent);
111 }
112 
113 EventStates
IntrinsicState() const114 nsGenConImageContent::IntrinsicState() const
115 {
116   EventStates state = nsXMLElement::IntrinsicState();
117 
118   EventStates imageState = nsImageLoadingContent::ImageState();
119   if (imageState.HasAtLeastOneOfStates(NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_USERDISABLED)) {
120     // We should never be in an error state; if the image fails to load, we
121     // just go to the suppressed state.
122     imageState |= NS_EVENT_STATE_SUPPRESSED;
123     imageState &= ~NS_EVENT_STATE_BROKEN;
124   }
125   imageState &= ~NS_EVENT_STATE_LOADING;
126   return state | imageState;
127 }
128