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 (1aeaa33a64f9)

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 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
/* -*- 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 ROTATEDBUFFER_H_
#define ROTATEDBUFFER_H_

#include "gfxTypes.h"
#include <stdint.h>                        // for uint32_t
#include "mozilla/Assertions.h"            // for MOZ_ASSERT, etc
#include "mozilla/RefPtr.h"                // for RefPtr, already_AddRefed
#include "mozilla/gfx/2D.h"                // for DrawTarget, etc
#include "mozilla/gfx/MatrixFwd.h"         // for Matrix
#include "mozilla/layers/TextureClient.h"  // for TextureClient
#include "mozilla/mozalloc.h"              // for operator delete
#include "nsCOMPtr.h"                      // for already_AddRefed
#include "nsISupportsImpl.h"               // for MOZ_COUNT_CTOR, etc
#include "nsRegion.h"                      // for nsIntRegion
#include "LayersTypes.h"

namespace mozilla {
namespace layers {

class PaintedLayer;
class CapturedBufferState;
class ContentClient;

// Mixin class for classes which need logic for loaning out a draw target.
// See comments on BorrowDrawTargetForQuadrantUpdate.
class BorrowDrawTarget {
 public:
  void ReturnDrawTarget(gfx::DrawTarget*& aReturned);

 protected:
  // The draw target loaned by BorrowDrawTargetForQuadrantUpdate. It should not
  // be used, we just keep a reference to ensure it is kept alive and so we can
  // correctly restore state when it is returned.
  RefPtr<gfx::DrawTarget> mLoanedDrawTarget;
  gfx::Matrix mLoanedTransform;

  // This flag denotes whether or not a transform was already applied
  // to mLoanedDrawTarget and thus needs to be reset to mLoanedTransform
  // upon returning the drawtarget.
  bool mSetTransform;
};

/**
 * This is a cairo/Thebes surface, but with a literal twist. Scrolling
 * causes the layer's visible region to move. We want to keep
 * reusing the same surface if the region size hasn't changed, but we don't
 * want to keep moving the contents of the surface around in memory. So
 * we use a trick.
 * Consider just the vertical case, and suppose the buffer is H pixels
 * high and we're scrolling down by N pixels. Instead of copying the
 * buffer contents up by N pixels, we leave the buffer contents in place,
 * and paint content rows H to H+N-1 into rows 0 to N-1 of the buffer.
 * Then we can refresh the screen by painting rows N to H-1 of the buffer
 * at row 0 on the screen, and then painting rows 0 to N-1 of the buffer
 * at row H-N on the screen.
 * mBufferRotation.y would be N in this example.
 */
class RotatedBuffer : public BorrowDrawTarget {
 public:
  typedef gfxContentType ContentType;

  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RotatedBuffer)

  RotatedBuffer(const gfx::IntRect& aBufferRect,
                const gfx::IntPoint& aBufferRotation)
      : mBufferRect(aBufferRect),
        mBufferRotation(aBufferRotation),
        mDidSelfCopy(false) {}
  RotatedBuffer() : mDidSelfCopy(false) {}

  /*
   * Which buffer should be drawn to/read from.
   */
  enum ContextSource {
    BUFFER_BLACK,  // The normal buffer, or buffer with black background when
                   // using component alpha.
    BUFFER_WHITE,  // The buffer with white background, only valid with
                   // component alpha.
    BUFFER_BOTH    // The combined black/white buffers, only valid for writing
                   // operations, not reading.
  };

  /**
   * Draws the contents of this rotated buffer into the specified draw target.
   * It is the callers repsonsibility to ensure aTarget is flushed after calling
   * this method.
   */
  void DrawBufferWithRotation(
      gfx::DrawTarget* aTarget, ContextSource aSource, float aOpacity = 1.0,
      gfx::CompositionOp aOperator = gfx::CompositionOp::OP_OVER,
      gfx::SourceSurface* aMask = nullptr,
      const gfx::Matrix* aMaskTransform = nullptr) const;

  /**
   * Complete the drawing operation. The region to draw must have been
   * drawn before this is called. The contents of the buffer are drawn
   * to aTarget.
   */
  void DrawTo(PaintedLayer* aLayer, gfx::DrawTarget* aTarget, float aOpacity,
              gfx::CompositionOp aOp, gfx::SourceSurface* aMask,
              const gfx::Matrix* aMaskTransform);

  /**
   * Update the specified region of this rotated buffer with the contents
   * of a source rotated buffer.
   */
  void UpdateDestinationFrom(const RotatedBuffer& aSource,
                             const gfx::IntRect& aUpdateRect);

  /**
   * A draw iterator is used to keep track of which quadrant of a rotated
   * buffer and region of that quadrant is being updated.
   */
  struct DrawIterator {
    friend class RotatedBuffer;
    DrawIterator() : mCount(0) {}

    nsIntRegion mDrawRegion;

   private:
    uint32_t mCount;
  };

  /**
   * Get a draw target at the specified resolution for updating |aBounds|,
   * which must be contained within a single quadrant.
   *
   * The result should only be held temporarily by the caller (it will be kept
   * alive by this). Once used it should be returned using ReturnDrawTarget.
   * BorrowDrawTargetForQuadrantUpdate may not be called more than once without
   * first calling ReturnDrawTarget.
   *
   * ReturnDrawTarget will by default restore the transform on the draw target.
   * But it is the callers responsibility to restore the clip.
   * The caller should flush the draw target, if necessary.
   * If aSetTransform is false, the required transform will be set in
   * aOutTransform.
   */
  gfx::DrawTarget* BorrowDrawTargetForQuadrantUpdate(
      const gfx::IntRect& aBounds, ContextSource aSource, DrawIterator* aIter,
      bool aSetTransform = true, gfx::Matrix* aOutTransform = nullptr);

  struct Parameters {
    Parameters(const gfx::IntRect& aBufferRect,
               const gfx::IntPoint& aBufferRotation)
        : mBufferRect(aBufferRect),
          mBufferRotation(aBufferRotation),
          mDidSelfCopy(false) {}

    bool IsRotated() const;
    bool RectWrapsBuffer(const gfx::IntRect& aRect) const;

    void SetUnrotated();

    gfx::IntRect mBufferRect;
    gfx::IntPoint mBufferRotation;
    bool mDidSelfCopy;
  };

  /**
   * Returns the new buffer parameters for rotating to a
   * destination buffer rect.
   */
  Parameters AdjustedParameters(const gfx::IntRect& aDestBufferRect) const;

  /**
   * Unrotates the pixels of the rotated buffer for the specified
   * new buffer parameters.
   */
  bool UnrotateBufferTo(const Parameters& aParameters);

  void SetParameters(const Parameters& aParameters);

  /**
   * |BufferRect()| is the rect of device pixels that this
   * RotatedBuffer covers.  That is what DrawBufferWithRotation()
   * will paint when it's called.
   */
  const gfx::IntRect& BufferRect() const { return mBufferRect; }
  const gfx::IntPoint& BufferRotation() const { return mBufferRotation; }

  /**
   * Overrides the current buffer rect with the specified rect.
   * Do not do this unless you know what you're doing.
   */
  void SetBufferRect(const gfx::IntRect& aBufferRect) {
    mBufferRect = aBufferRect;
  }

  /**
   * Overrides the current buffer rotation with the specified point.
   * Do not do this unless you know what you're doing.
   */
  void SetBufferRotation(const gfx::IntPoint& aBufferRotation) {
    mBufferRotation = aBufferRotation;
  }

  /**
   * Returns whether this buffer did a self copy when adjusting to
   * a new buffer rect. This is only used externally for syncing
   * rotated buffers.
   */
  bool DidSelfCopy() const { return mDidSelfCopy; }

  /**
   * Clears the self copy flag.
   */
  void ClearDidSelfCopy() { mDidSelfCopy = false; }

  /**
   * Gets the content type for this buffer.
   */
  ContentType GetContentType() const;

  virtual bool IsLocked() = 0;
  virtual bool Lock(OpenMode aMode) = 0;
  virtual void Unlock() = 0;

  virtual bool HaveBuffer() const = 0;
  virtual bool HaveBufferOnWhite() const = 0;

  virtual gfx::SurfaceFormat GetFormat() const = 0;

  virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(
      ContextSource aSource) const = 0;

  virtual gfx::DrawTarget* GetDTBuffer() const = 0;
  virtual gfx::DrawTarget* GetDTBufferOnWhite() const = 0;

  virtual TextureClient* GetClient() const { return nullptr; }
  virtual TextureClient* GetClientOnWhite() const { return nullptr; }

  /**
   * Creates a shallow copy of the rotated buffer with the same underlying
   * texture clients and draw targets. Rotated buffers are not thread safe,
   * so a copy needs to be sent for off main thread painting.
   */
  virtual RefPtr<RotatedBuffer> ShallowCopy() const = 0;

 protected:
  virtual ~RotatedBuffer() {}

  enum XSide { LEFT, RIGHT };
  enum YSide { TOP, BOTTOM };
  gfx::IntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide) const;

  gfx::Rect GetSourceRectangle(XSide aXSide, YSide aYSide) const;

  /*
   * If aMask is non-null, then it is used as an alpha mask for rendering this
   * buffer. aMaskTransform must be non-null if aMask is non-null, and is used
   * to adjust the coordinate space of the mask.
   */
  void DrawBufferQuadrant(gfx::DrawTarget* aTarget, XSide aXSide, YSide aYSide,
                          ContextSource aSource, float aOpacity,
                          gfx::CompositionOp aOperator,
                          gfx::SourceSurface* aMask,
                          const gfx::Matrix* aMaskTransform) const;

  /** The area of the PaintedLayer that is covered by the buffer as a whole */
  gfx::IntRect mBufferRect;
  /**
   * The x and y rotation of the buffer. Conceptually the buffer
   * has its origin translated to mBufferRect.TopLeft() - mBufferRotation,
   * is tiled to fill the plane, and the result is clipped to mBufferRect.
   * So the pixel at mBufferRotation within the buffer is what gets painted at
   * mBufferRect.TopLeft().
   * This is "rotation" in the sense of rotating items in a linear buffer,
   * where items falling off the end of the buffer are returned to the
   * buffer at the other end, not 2D rotation!
   */
  gfx::IntPoint mBufferRotation;
  /**
   * When this is true it means that all pixels have moved inside the buffer.
   * It's not possible to sync with another buffer without a full copy.
   */
  bool mDidSelfCopy;
};

/**
 * RemoteRotatedBuffer is a rotated buffer that is backed by texture
 * clients. Before you use this class you must successfully lock it with
 * an appropriate open mode, and then also unlock it when you're finished.
 * RemoteRotatedBuffer is used by ContentClientSingleBuffered and
 * ContentClientDoubleBuffered for the OMTC code path.
 */
class RemoteRotatedBuffer : public RotatedBuffer {
 public:
  RemoteRotatedBuffer(TextureClient* aClient, TextureClient* aClientOnWhite,
                      const gfx::IntRect& aBufferRect,
                      const gfx::IntPoint& aBufferRotation)
      : RotatedBuffer(aBufferRect, aBufferRotation),
        mClient(aClient),
        mClientOnWhite(aClientOnWhite) {}

  virtual bool IsLocked() override;
  virtual bool Lock(OpenMode aMode) override;
  virtual void Unlock() override;

  virtual bool HaveBuffer() const override { return !!mClient; }
  virtual bool HaveBufferOnWhite() const override { return !!mClientOnWhite; }

  virtual gfx::SurfaceFormat GetFormat() const override;

  virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(
      ContextSource aSource) const override;

  virtual gfx::DrawTarget* GetDTBuffer() const override;
  virtual gfx::DrawTarget* GetDTBufferOnWhite() const override;

  virtual TextureClient* GetClient() const override { return mClient; }
  virtual TextureClient* GetClientOnWhite() const override {
    return mClientOnWhite;
  }

  virtual RefPtr<RotatedBuffer> ShallowCopy() const override {
    return new RemoteRotatedBuffer{mClient,     mClientOnWhite,
                                   mTarget,     mTargetOnWhite,
                                   mBufferRect, mBufferRotation};
  }

  void SyncWithObject(SyncObjectClient* aSyncObject);
  void Clear();

 private:
  RemoteRotatedBuffer(TextureClient* aClient, TextureClient* aClientOnWhite,
                      gfx::DrawTarget* aTarget, gfx::DrawTarget* aTargetOnWhite,
                      const gfx::IntRect& aBufferRect,
                      const gfx::IntPoint& aBufferRotation)
      : RotatedBuffer(aBufferRect, aBufferRotation),
        mClient(aClient),
        mClientOnWhite(aClientOnWhite),
        mTarget(aTarget),
        mTargetOnWhite(aTargetOnWhite) {}

  RefPtr<TextureClient> mClient;
  RefPtr<TextureClient> mClientOnWhite;

  RefPtr<gfx::DrawTarget> mTarget;
  RefPtr<gfx::DrawTarget> mTargetOnWhite;
};

/**
 * DrawTargetRotatedBuffer is a rotated buffer that is backed by draw targets,
 * and is used by ContentClientBasic for the on-mtc code path.
 */
class DrawTargetRotatedBuffer : public RotatedBuffer {
 public:
  DrawTargetRotatedBuffer(gfx::DrawTarget* aTarget,
                          gfx::DrawTarget* aTargetOnWhite,
                          const gfx::IntRect& aBufferRect,
                          const gfx::IntPoint& aBufferRotation)
      : RotatedBuffer(aBufferRect, aBufferRotation),
        mTarget(aTarget),
        mTargetOnWhite(aTargetOnWhite) {}

  virtual bool IsLocked() override { return false; }
  virtual bool Lock(OpenMode aMode) override { return true; }
  virtual void Unlock() override {}

  virtual bool HaveBuffer() const override { return !!mTarget; }
  virtual bool HaveBufferOnWhite() const override { return !!mTargetOnWhite; }

  virtual gfx::SurfaceFormat GetFormat() const override;

  virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(
      ContextSource aSource) const override;

  virtual gfx::DrawTarget* GetDTBuffer() const override;
  virtual gfx::DrawTarget* GetDTBufferOnWhite() const override;

  virtual RefPtr<RotatedBuffer> ShallowCopy() const override {
    return new DrawTargetRotatedBuffer{mTarget, mTargetOnWhite, mBufferRect,
                                       mBufferRotation};
  }

 private:
  RefPtr<gfx::DrawTarget> mTarget;
  RefPtr<gfx::DrawTarget> mTargetOnWhite;
};

/**
 * SourceRotatedBuffer is a rotated buffer that is backed by source surfaces,
 * and may only be used to draw into other buffers or be read directly.
 */
class SourceRotatedBuffer : public RotatedBuffer {
 public:
  SourceRotatedBuffer(gfx::SourceSurface* aSource,
                      gfx::SourceSurface* aSourceOnWhite,
                      const gfx::IntRect& aBufferRect,
                      const gfx::IntPoint& aBufferRotation)
      : RotatedBuffer(aBufferRect, aBufferRotation),
        mSource(aSource),
        mSourceOnWhite(aSourceOnWhite) {}

  virtual bool IsLocked() override { return false; }
  virtual bool Lock(OpenMode aMode) override { return false; }
  virtual void Unlock() override {}

  virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(
      ContextSource aSource) const override;

  virtual gfx::SurfaceFormat GetFormat() const override;

  virtual bool HaveBuffer() const override { return !!mSource; }
  virtual bool HaveBufferOnWhite() const override { return !!mSourceOnWhite; }

  virtual gfx::DrawTarget* GetDTBuffer() const override { return nullptr; }
  virtual gfx::DrawTarget* GetDTBufferOnWhite() const override {
    return nullptr;
  }

  virtual RefPtr<RotatedBuffer> ShallowCopy() const override { return nullptr; }

 private:
  RefPtr<gfx::SourceSurface> mSource;
  RefPtr<gfx::SourceSurface> mSourceOnWhite;
};

}  // namespace layers
}  // namespace mozilla

#endif /* ROTATEDBUFFER_H_ */