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.

Mercurial (56e7b9127e89)

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
/* -*- 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 MOZILLA_PAINTING_TRANSFORMCLIPNODE_H
#define MOZILLA_PAINTING_TRANSFORMCLIPNODE_H

#include "mozilla/gfx/MatrixFwd.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/Maybe.h"
#include "nsISupports.h"
#include "nsRegionFwd.h"

namespace mozilla {

/**
 * TransformClipNode stores a transformation matrix and a post-transform
 * clip rect.
 * They can be used to transform and clip a display item inside a flattened
 * nsDisplayTransform to the coordinate space of that nsDisplayTransform.
 */
class TransformClipNode {
  NS_INLINE_DECL_REFCOUNTING(TransformClipNode);
public:
  TransformClipNode(const RefPtr<TransformClipNode>& aParent,
                    const gfx::Matrix4x4Flagged& aTransform,
                    const Maybe<nsRect>& aClip)
  : mParent(aParent)
  , mTransform(aTransform)
  , mClip(aClip)
  {
    MOZ_COUNT_CTOR(TransformClipNode);
  }

  /**
   * Returns the parent node, or nullptr if this is the root node.
   */
  const RefPtr<TransformClipNode>& Parent() const
  {
    return mParent;
  }

  /**
   * Transforms and clips |aRect| up to the root transform node.
   * |aRect| is expected to be in app units.
   */
  nsRect TransformRect(const nsRect& aRect, const int32_t aA2D)
  {
    if (aRect.IsEmpty()) {
      return aRect;
    }

    gfx::Rect result(NSAppUnitsToFloatPixels(aRect.x, aA2D),
                     NSAppUnitsToFloatPixels(aRect.y, aA2D),
                     NSAppUnitsToFloatPixels(aRect.width, aA2D),
                     NSAppUnitsToFloatPixels(aRect.height, aA2D));
    TransformRect(result, aA2D);
    return nsRect(NSFloatPixelsToAppUnits(result.x, aA2D),
                  NSFloatPixelsToAppUnits(result.y, aA2D),
                  NSFloatPixelsToAppUnits(result.width, aA2D),
                  NSFloatPixelsToAppUnits(result.height, aA2D));
  }

  /**
   * Transforms and clips |aRect| up to the root transform node.
   * |aRect| is expected to be in integer pixels.
   */
  gfx::IntRect TransformRect(const gfx::IntRect& aRect, const int32_t aA2D)
  {
    if (aRect.IsEmpty()) {
      return aRect;
    }

    gfx::Rect result(IntRectToRect(aRect));
    TransformRect(result, aA2D);
    return RoundedToInt(result);
  }

  /**
   * Transforms and clips |aRegion| up to the root transform node.
   * |aRegion| is expected be in integer pixels.
   */
  nsIntRegion TransformRegion(const nsIntRegion& aRegion, const int32_t aA2D)
  {
    if (aRegion.IsEmpty()) {
      return aRegion;
    }

    nsIntRegion result = aRegion;

    const TransformClipNode* node = this;
    while (node) {
      const gfx::Matrix4x4Flagged& transform = node->Transform();
      result = result.Transform(transform.GetMatrix());

      if (node->Clip()) {
        const nsRect& clip = *node->Clip();
        const gfx::IntRect clipRect = clip.ToNearestPixels(aA2D);
        result.AndWith(clipRect);
      }

      node = node->Parent();
    }

    return result;
  }

protected:
  /**
   * Returns the post-transform clip, if there is one.
   */
  const Maybe<nsRect>& Clip() const
  {
    return mClip;
  }

  /**
   * Returns the matrix that transforms the item bounds to the coordinate space
   * of the flattened nsDisplayTransform.
   */
  const gfx::Matrix4x4Flagged& Transform() const
  {
    return mTransform;
  }

  void TransformRect(gfx::Rect& aRect, const int32_t aA2D)
  {
    const TransformClipNode* node = this;
    while (node) {
      const gfx::Matrix4x4Flagged& transform = node->Transform();
      gfx::Rect maxBounds = gfx::Rect::MaxIntRect();

      if (node->Clip()) {
        const nsRect& clip = *node->Clip();
        maxBounds = IntRectToRect(clip.ToNearestPixels(aA2D));
      }

      aRect = transform.TransformAndClipBounds(aRect, maxBounds);
      node = node->Parent();
    }
  }

private:
  ~TransformClipNode()
  {
    MOZ_COUNT_DTOR(TransformClipNode);
  }

  const RefPtr<TransformClipNode> mParent;
  const gfx::Matrix4x4Flagged mTransform;
  const Maybe<nsRect> mClip;
};

} // namespace mozilla

#endif /* MOZILLA_PAINTING_TRANSFORMCLIPNODE_H */