diff -r 000000000000 -r 6474c204b198 layout/generic/nsImageFrame.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layout/generic/nsImageFrame.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,408 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* rendering object for replaced elements with bitmap image data */ + +#ifndef nsImageFrame_h___ +#define nsImageFrame_h___ + +#include "nsSplittableFrame.h" +#include "nsIIOService.h" +#include "nsIObserver.h" + +#include "imgINotificationObserver.h" + +#include "nsDisplayList.h" +#include "imgIContainer.h" +#include "mozilla/Attributes.h" +#include "mozilla/DebugOnly.h" +#include "nsIReflowCallback.h" + +class nsImageMap; +class nsIURI; +class nsILoadGroup; +struct nsHTMLReflowState; +struct nsHTMLReflowMetrics; +class nsDisplayImage; +class nsPresContext; +class nsImageFrame; +class nsTransform2D; +class nsImageLoadingContent; + +namespace mozilla { +namespace layers { + class ImageContainer; + class ImageLayer; + class LayerManager; +} +} + +class nsImageListener : public imgINotificationObserver +{ +public: + nsImageListener(nsImageFrame *aFrame); + virtual ~nsImageListener(); + + NS_DECL_ISUPPORTS + NS_DECL_IMGINOTIFICATIONOBSERVER + + void SetFrame(nsImageFrame *frame) { mFrame = frame; } + +private: + nsImageFrame *mFrame; +}; + +typedef nsSplittableFrame ImageFrameSuper; + +class nsImageFrame : public ImageFrameSuper, + public nsIReflowCallback { +public: + typedef mozilla::layers::ImageContainer ImageContainer; + typedef mozilla::layers::ImageLayer ImageLayer; + typedef mozilla::layers::LayerManager LayerManager; + + NS_DECL_FRAMEARENA_HELPERS + + nsImageFrame(nsStyleContext* aContext); + + NS_DECL_QUERYFRAME_TARGET(nsImageFrame) + NS_DECL_QUERYFRAME + + virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; + virtual void Init(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame* aPrevInFlow) MOZ_OVERRIDE; + virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) MOZ_OVERRIDE; + virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; + virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; + virtual mozilla::IntrinsicSize GetIntrinsicSize() MOZ_OVERRIDE; + virtual nsSize GetIntrinsicRatio() MOZ_OVERRIDE; + virtual nsresult Reflow(nsPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) MOZ_OVERRIDE; + + virtual nsresult GetContentForEvent(mozilla::WidgetEvent* aEvent, + nsIContent** aContent) MOZ_OVERRIDE; + virtual nsresult HandleEvent(nsPresContext* aPresContext, + mozilla::WidgetGUIEvent* aEvent, + nsEventStatus* aEventStatus) MOZ_OVERRIDE; + virtual nsresult GetCursor(const nsPoint& aPoint, + nsIFrame::Cursor& aCursor) MOZ_OVERRIDE; + virtual nsresult AttributeChanged(int32_t aNameSpaceID, + nsIAtom* aAttribute, + int32_t aModType) MOZ_OVERRIDE; + +#ifdef ACCESSIBILITY + virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE; +#endif + + virtual nsIAtom* GetType() const MOZ_OVERRIDE; + + virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE + { + return ImageFrameSuper::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced)); + } + +#ifdef DEBUG_FRAME_DUMP + virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; + void List(FILE* out = stderr, const char* aPrefix = "", + uint32_t aFlags = 0) const MOZ_OVERRIDE; +#endif + + virtual int GetLogicalSkipSides(const nsHTMLReflowState* aReflowState = nullptr) const MOZ_OVERRIDE; + + nsresult GetIntrinsicImageSize(nsSize& aSize); + + static void ReleaseGlobals() { + if (gIconLoad) { + gIconLoad->Shutdown(); + NS_RELEASE(gIconLoad); + } + NS_IF_RELEASE(sIOService); + } + + nsresult Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData); + + /** + * Function to test whether aContent, which has aStyleContext as its style, + * should get an image frame. Note that this method is only used by the + * frame constructor; it's only here because it uses gIconLoad for now. + */ + static bool ShouldCreateImageFrameFor(mozilla::dom::Element* aElement, + nsStyleContext* aStyleContext); + + void DisplayAltFeedback(nsRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + imgIRequest* aRequest, + nsPoint aPt); + + nsRect GetInnerArea() const; + + /** + * Return a map element associated with this image. + */ + mozilla::dom::Element* GetMapElement() const + { + nsAutoString usemap; + if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usemap, usemap)) { + return mContent->OwnerDoc()->FindImageMap(usemap); + } + return nullptr; + } + + /** + * Return true if the image has associated image map. + */ + bool HasImageMap() const { return mImageMap || GetMapElement(); } + + nsImageMap* GetImageMap(); + nsImageMap* GetExistingImageMap() const { return mImageMap; } + + virtual void AddInlineMinWidth(nsRenderingContext *aRenderingContext, + InlineMinWidthData *aData) MOZ_OVERRIDE; + + void DisconnectMap(); + + // nsIReflowCallback + virtual bool ReflowFinished() MOZ_OVERRIDE; + virtual void ReflowCallbackCanceled() MOZ_OVERRIDE; + +protected: + virtual ~nsImageFrame(); + + void EnsureIntrinsicSizeAndRatio(nsPresContext* aPresContext); + + virtual nsSize ComputeSize(nsRenderingContext *aRenderingContext, + nsSize aCBSize, nscoord aAvailableWidth, + nsSize aMargin, nsSize aBorder, nsSize aPadding, + uint32_t aFlags) MOZ_OVERRIDE; + + bool IsServerImageMap(); + + void TranslateEventCoords(const nsPoint& aPoint, + nsIntPoint& aResult); + + bool GetAnchorHREFTargetAndNode(nsIURI** aHref, nsString& aTarget, + nsIContent** aNode); + /** + * Computes the width of the string that fits into the available space + * + * @param in aLength total length of the string in PRUnichars + * @param in aMaxWidth width not to be exceeded + * @param out aMaxFit length of the string that fits within aMaxWidth + * in PRUnichars + * @return width of the string that fits within aMaxWidth + */ + nscoord MeasureString(const char16_t* aString, + int32_t aLength, + nscoord aMaxWidth, + uint32_t& aMaxFit, + nsRenderingContext& aContext); + + void DisplayAltText(nsPresContext* aPresContext, + nsRenderingContext& aRenderingContext, + const nsString& aAltText, + const nsRect& aRect); + + void PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt, + const nsRect& aDirtyRect, imgIContainer* aImage, + uint32_t aFlags); + +protected: + friend class nsImageListener; + friend class nsImageLoadingContent; + nsresult OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage); + nsresult OnDataAvailable(imgIRequest *aRequest, const nsIntRect *rect); + nsresult OnStopRequest(imgIRequest *aRequest, + nsresult aStatus); + nsresult FrameChanged(imgIRequest *aRequest, + imgIContainer *aContainer); + /** + * Notification that aRequest will now be the current request. + */ + void NotifyNewCurrentRequest(imgIRequest *aRequest, nsresult aStatus); + +private: + // random helpers + inline void SpecToURI(const nsAString& aSpec, nsIIOService *aIOService, + nsIURI **aURI); + + inline void GetLoadGroup(nsPresContext *aPresContext, + nsILoadGroup **aLoadGroup); + nscoord GetContinuationOffset() const; + void GetDocumentCharacterSet(nsACString& aCharset) const; + bool ShouldDisplaySelection(); + + /** + * Recalculate mIntrinsicSize from the image. + * + * @return whether aImage's size did _not_ + * match our previous intrinsic size. + */ + bool UpdateIntrinsicSize(imgIContainer* aImage); + + /** + * Recalculate mIntrinsicRatio from the image. + * + * @return whether aImage's ratio did _not_ + * match our previous intrinsic ratio. + */ + bool UpdateIntrinsicRatio(imgIContainer* aImage); + + /** + * This function calculates the transform for converting between + * source space & destination space. May fail if our image has a + * percent-valued or zero-valued height or width. + * + * @param aTransform The transform object to populate. + * + * @return whether we succeeded in creating the transform. + */ + bool GetSourceToDestTransform(nsTransform2D& aTransform); + + /** + * Helper functions to check whether the request or image container + * corresponds to a load we don't care about. Most of the decoder + * observer methods will bail early if these return true. + */ + bool IsPendingLoad(imgIRequest* aRequest) const; + bool IsPendingLoad(imgIContainer* aContainer) const; + + /** + * Function to convert a dirty rect in the source image to a dirty + * rect for the image frame. + */ + nsRect SourceRectToDest(const nsIntRect & aRect); + + nsImageMap* mImageMap; + + nsCOMPtr mListener; + + nsCOMPtr mImage; + nsSize mComputedSize; + mozilla::IntrinsicSize mIntrinsicSize; + nsSize mIntrinsicRatio; + + bool mDisplayingIcon; + bool mFirstFrameComplete; + bool mReflowCallbackPosted; + + static nsIIOService* sIOService; + + /* loading / broken image icon support */ + + // XXXbz this should be handled by the prescontext, I think; that + // way we would have a single iconload per mozilla session instead + // of one per document... + + // LoadIcons: initiate the loading of the static icons used to show + // loading / broken images + nsresult LoadIcons(nsPresContext *aPresContext); + nsresult LoadIcon(const nsAString& aSpec, nsPresContext *aPresContext, + imgRequestProxy **aRequest); + + class IconLoad MOZ_FINAL : public nsIObserver, + public imgINotificationObserver { + // private class that wraps the data and logic needed for + // broken image and loading image icons + public: + IconLoad(); + + void Shutdown(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + NS_DECL_IMGINOTIFICATIONOBSERVER + + void AddIconObserver(nsImageFrame *frame) { + NS_ABORT_IF_FALSE(!mIconObservers.Contains(frame), + "Observer shouldn't aleady be in array"); + mIconObservers.AppendElement(frame); + } + + void RemoveIconObserver(nsImageFrame *frame) { + mozilla::DebugOnly didRemove = mIconObservers.RemoveElement(frame); + NS_ABORT_IF_FALSE(didRemove, "Observer not in array"); + } + + private: + void GetPrefs(); + nsTObserverArray mIconObservers; + + + public: + nsRefPtr mLoadingImage; + nsRefPtr mBrokenImage; + bool mPrefForceInlineAltText; + bool mPrefShowPlaceholders; + }; + +public: + static IconLoad* gIconLoad; // singleton pattern: one LoadIcons instance is used + + friend class nsDisplayImage; +}; + +/** + * Note that nsDisplayImage does not receive events. However, an image element + * is replaced content so its background will be z-adjacent to the + * image itself, and hence receive events just as if the image itself + * received events. + */ +class nsDisplayImage : public nsDisplayImageContainer { +public: + typedef mozilla::layers::LayerManager LayerManager; + + nsDisplayImage(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame, + imgIContainer* aImage) + : nsDisplayImageContainer(aBuilder, aFrame), mImage(aImage) { + MOZ_COUNT_CTOR(nsDisplayImage); + } + virtual ~nsDisplayImage() { + MOZ_COUNT_DTOR(nsDisplayImage); + } + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) MOZ_OVERRIDE; + virtual void Paint(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx) MOZ_OVERRIDE; + + /** + * Returns an ImageContainer for this image if the image type + * supports it (TYPE_RASTER only). + */ + virtual already_AddRefed GetContainer(LayerManager* aManager, + nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; + + gfxRect GetDestRect(); + + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) MOZ_OVERRIDE; + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE + { + *aSnap = true; + return nsRect(ToReferenceFrame(), Frame()->GetSize()); + } + + virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; + + /** + * Configure an ImageLayer for this display item. + * Set the required filter and scaling transform. + */ + virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) MOZ_OVERRIDE; + + NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE) +private: + nsCOMPtr mImage; +}; + +#endif /* nsImageFrame_h___ */