DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (409f3966645a)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */

#ifndef nsImageRenderer_h__
#define nsImageRenderer_h__

#include "nsLayoutUtils.h"
#include "nsStyleStruct.h"
#include "Units.h"

class gfxDrawable;
namespace mozilla {

namespace layers {
class StackingContextHelper;
class WebRenderParentCommand;
class WebRenderLayerManager;
} // namespace layers

namespace wr {
class DisplayListBuilder;
class IpcResourceUpdateQueue;
} // namespace wr

// A CSSSizeOrRatio represents a (possibly partially specified) size for use
// in computing image sizes. Either or both of the width and height might be
// given. A ratio of width to height may also be given. If we at least two
// of these then we can compute a concrete size, that is a width and height.
struct CSSSizeOrRatio
{
  CSSSizeOrRatio()
    : mRatio(0, 0)
    , mWidth(0)
    , mHeight(0)
    , mHasWidth(false)
    , mHasHeight(false)
  {
  }

  bool CanComputeConcreteSize() const
  {
    return mHasWidth + mHasHeight + HasRatio() >= 2;
  }
  bool IsConcrete() const { return mHasWidth && mHasHeight; }
  bool HasRatio() const { return mRatio.width > 0 && mRatio.height > 0; }
  bool IsEmpty() const
  {
    return (mHasWidth && mWidth <= 0) || (mHasHeight && mHeight <= 0) ||
           mRatio.width <= 0 || mRatio.height <= 0;
  }

  // CanComputeConcreteSize must return true when ComputeConcreteSize is
  // called.
  nsSize ComputeConcreteSize() const;

  void SetWidth(nscoord aWidth)
  {
    mWidth = aWidth;
    mHasWidth = true;
    if (mHasHeight) {
      mRatio = nsSize(mWidth, mHeight);
    }
  }
  void SetHeight(nscoord aHeight)
  {
    mHeight = aHeight;
    mHasHeight = true;
    if (mHasWidth) {
      mRatio = nsSize(mWidth, mHeight);
    }
  }
  void SetSize(const nsSize& aSize)
  {
    mWidth = aSize.width;
    mHeight = aSize.height;
    mHasWidth = true;
    mHasHeight = true;
    mRatio = aSize;
  }
  void SetRatio(const nsSize& aRatio)
  {
    MOZ_ASSERT(
      !mHasWidth || !mHasHeight,
      "Probably shouldn't be setting a ratio if we have a concrete size");
    mRatio = aRatio;
  }

  nsSize mRatio;
  nscoord mWidth;
  nscoord mHeight;
  bool mHasWidth;
  bool mHasHeight;
};

/**
 * This is a small wrapper class to encapsulate image drawing that can draw an
 * nsStyleImage image, which may internally be a real image, a sub image, or a
 * CSS gradient.
 *
 * @note Always call the member functions in the order of PrepareImage(),
 * SetSize(), and Draw*().
 */
class nsImageRenderer
{
public:
  typedef mozilla::image::ImgDrawResult ImgDrawResult;
  typedef mozilla::layers::LayerManager LayerManager;
  typedef mozilla::layers::ImageContainer ImageContainer;

  enum
  {
    FLAG_SYNC_DECODE_IMAGES = 0x01,
    FLAG_PAINTING_TO_WINDOW = 0x02
  };
  enum FitType
  {
    CONTAIN,
    COVER
  };

  nsImageRenderer(nsIFrame* aForFrame,
                  const nsStyleImage* aImage,
                  uint32_t aFlags);
  ~nsImageRenderer() = default;
  /**
   * Populates member variables to get ready for rendering.
   * @return true iff the image is ready, and there is at least a pixel to
   * draw.
   */
  bool PrepareImage();

  /**
   * The three Compute*Size functions correspond to the sizing algorthms and
   * definitions from the CSS Image Values and Replaced Content spec. See
   * http://dev.w3.org/csswg/css-images-3/#sizing .
   */

  /**
   * Compute the intrinsic size of the image as defined in the CSS Image Values
   * spec. The intrinsic size is the unscaled size which the image would ideally
   * like to be in app units.
   */
  mozilla::CSSSizeOrRatio ComputeIntrinsicSize();

  /**
   * Computes the placement for a background image, or for the image data
   * inside of a replaced element.
   *
   * @param aPos The CSS <position> value that specifies the image's position.
   * @param aOriginBounds The box to which the tiling position should be
   *          relative. For background images, this should correspond to
   *          'background-origin' for the frame, except when painting on the
   *          canvas, in which case the origin bounds should be the bounds
   *          of the root element's frame. For a replaced element, this should
   *          be the element's content-box.
   * @param aTopLeft [out] The top-left corner where an image tile should be
   *          drawn.
   * @param aAnchorPoint [out] A point which should be pixel-aligned by
   *          nsLayoutUtils::DrawImage. This is the same as aTopLeft, unless
   *          CSS specifies a percentage (including 'right' or 'bottom'), in
   *          which case it's that percentage within of aOriginBounds. So
   *          'right' would set aAnchorPoint.x to aOriginBounds.XMost().
   *
   * Points are returned relative to aOriginBounds.
   */
  static void ComputeObjectAnchorPoint(const mozilla::Position& aPos,
                                       const nsSize& aOriginBounds,
                                       const nsSize& aImageSize,
                                       nsPoint* aTopLeft,
                                       nsPoint* aAnchorPoint);

  /**
   * Compute the size of the rendered image using either the 'cover' or
   * 'contain' constraints (aFitType).
   * aIntrinsicRatio may be an invalid ratio, that is one or both of its
   * dimensions can be less than or equal to zero.
   */
  static nsSize ComputeConstrainedSize(const nsSize& aConstrainingSize,
                                       const nsSize& aIntrinsicRatio,
                                       FitType aFitType);
  /**
   * Compute the size of the rendered image (the concrete size) where no cover/
   * contain constraints are given. The 'default algorithm' from the CSS Image
   * Values spec.
   */
  static nsSize ComputeConcreteSize(
    const mozilla::CSSSizeOrRatio& aSpecifiedSize,
    const mozilla::CSSSizeOrRatio& aIntrinsicSize,
    const nsSize& aDefaultSize);

  /**
   * Set this image's preferred size. This will be its intrinsic size where
   * specified and the default size where it is not. Used as the unscaled size
   * when rendering the image.
   */
  void SetPreferredSize(const mozilla::CSSSizeOrRatio& aIntrinsicSize,
                        const nsSize& aDefaultSize);

  /**
   * Draws the image to the target rendering context using
   * {background|mask}-specific arguments.
   * @see nsLayoutUtils::DrawImage() for parameters.
   */
  ImgDrawResult DrawLayer(nsPresContext* aPresContext,
                          gfxContext& aRenderingContext,
                          const nsRect& aDest,
                          const nsRect& aFill,
                          const nsPoint& aAnchor,
                          const nsRect& aDirty,
                          const nsSize& aRepeatSize,
                          float aOpacity);

  /**
   * Builds WebRender DisplayItems for an image using
   * {background|mask}-specific arguments.
   * @see nsLayoutUtils::DrawImage() for parameters.
   */
  ImgDrawResult BuildWebRenderDisplayItemsForLayer(
    nsPresContext* aPresContext,
    mozilla::wr::DisplayListBuilder& aBuilder,
    mozilla::wr::IpcResourceUpdateQueue& aResource,
    const mozilla::layers::StackingContextHelper& aSc,
    mozilla::layers::WebRenderLayerManager* aManager,
    nsDisplayItem* aItem,
    const nsRect& aDest,
    const nsRect& aFill,
    const nsPoint& aAnchor,
    const nsRect& aDirty,
    const nsSize& aRepeatSize,
    float aOpacity);

  /**
   * Draw the image to a single component of a border-image style rendering.
   * aFill The destination rect to be drawn into
   * aSrc is the part of the image to be rendered into a tile (aUnitSize in
   * aFill), if aSrc and the dest tile are different sizes, the image will be
   * scaled to map aSrc onto the dest tile.
   * aHFill and aVFill are the repeat patterns for the component -
   * NS_STYLE_BORDER_IMAGE_REPEAT_*
   * aUnitSize The scaled size of a single source rect (in destination coords)
   * aIndex identifies the component: 0 1 2
   *                                  3 4 5
   *                                  6 7 8
   * aSVGViewportSize The image size evaluated by default sizing algorithm.
   * Pass Nothing() if we can read a valid viewport size or aspect-ratio from
   * the drawing image directly, otherwise, pass Some() with viewport size
   * evaluated from default sizing algorithm.
   * aHasIntrinsicRatio is used to record if the source image has fixed
   * intrinsic ratio.
   */
  ImgDrawResult DrawBorderImageComponent(
    nsPresContext* aPresContext,
    gfxContext& aRenderingContext,
    const nsRect& aDirtyRect,
    const nsRect& aFill,
    const mozilla::CSSIntRect& aSrc,
    mozilla::StyleBorderImageRepeat aHFill,
    mozilla::StyleBorderImageRepeat aVFill,
    const nsSize& aUnitSize,
    uint8_t aIndex,
    const mozilla::Maybe<nsSize>& aSVGViewportSize,
    const bool aHasIntrinsicRatio);

  /**
   * Draw the image to aRenderingContext which can be used to define the
   * float area in the presence of "shape-outside: <image>".
   */
  ImgDrawResult DrawShapeImage(nsPresContext* aPresContext,
                               gfxContext& aRenderingContext);

  bool IsRasterImage();
  bool IsAnimatedImage();

  /// Retrieves the image associated with this nsImageRenderer, if there is one.
  already_AddRefed<imgIContainer> GetImage();

  bool IsImageContainerAvailable(layers::LayerManager* aManager,
                                 uint32_t aFlags);
  bool IsReady() const { return mPrepareResult == ImgDrawResult::SUCCESS; }
  ImgDrawResult PrepareResult() const { return mPrepareResult; }
  void SetExtendMode(mozilla::gfx::ExtendMode aMode) { mExtendMode = aMode; }
  void SetMaskOp(uint8_t aMaskOp) { mMaskOp = aMaskOp; }
  void PurgeCacheForViewportChange(
    const mozilla::Maybe<nsSize>& aSVGViewportSize,
    const bool aHasRatio);
  nsStyleImageType GetType() const { return mType; }
  already_AddRefed<nsStyleGradient> GetGradientData();

private:
  /**
   * Draws the image to the target rendering context.
   * aSrc is a rect on the source image which will be mapped to aDest; it's
   * currently only used for gradients.
   *
   * @see nsLayoutUtils::DrawImage() for other parameters.
   */
  ImgDrawResult Draw(nsPresContext* aPresContext,
                     gfxContext& aRenderingContext,
                     const nsRect& aDirtyRect,
                     const nsRect& aDest,
                     const nsRect& aFill,
                     const nsPoint& aAnchor,
                     const nsSize& aRepeatSize,
                     const mozilla::CSSIntRect& aSrc,
                     float aOpacity = 1.0);

  /**
   * Builds WebRender DisplayItems for the image.
   * aSrc is a rect on the source image which will be mapped to aDest; it's
   * currently only used for gradients.
   *
   * @see nsLayoutUtils::DrawImage() for other parameters.
   */
  ImgDrawResult BuildWebRenderDisplayItems(
    nsPresContext* aPresContext,
    mozilla::wr::DisplayListBuilder& aBuilder,
    mozilla::wr::IpcResourceUpdateQueue& aResources,
    const mozilla::layers::StackingContextHelper& aSc,
    mozilla::layers::WebRenderLayerManager* aManager,
    nsDisplayItem* aItem,
    const nsRect& aDirtyRect,
    const nsRect& aDest,
    const nsRect& aFill,
    const nsPoint& aAnchor,
    const nsSize& aRepeatSize,
    const mozilla::CSSIntRect& aSrc,
    float aOpacity = 1.0);

  /**
   * Helper method for creating a gfxDrawable from mPaintServerFrame or
   * mImageElementSurface.
   * Requires mType is eStyleImageType_Element.
   * Returns null if we cannot create the drawable.
   */
  already_AddRefed<gfxDrawable> DrawableForElement(const nsRect& aImageRect,
                                                   gfxContext& aContext);

  nsIFrame* mForFrame;
  const nsStyleImage* mImage;
  nsStyleImageType mType;
  nsCOMPtr<imgIContainer> mImageContainer;
  RefPtr<nsStyleGradient> mGradientData;
  nsIFrame* mPaintServerFrame;
  nsLayoutUtils::SurfaceFromElementResult mImageElementSurface;
  ImgDrawResult mPrepareResult;
  nsSize mSize; // unscaled size of the image, in app units
  uint32_t mFlags;
  mozilla::gfx::ExtendMode mExtendMode;
  uint8_t mMaskOp;
};

} // namespace mozilla

#endif /* nsImageRenderer_h__ */