summaryrefslogtreecommitdiffstats
path: root/layout/painting/TransformClipNode.h
blob: a28dc3dbc04a864faf4322bb5fdff61f4b827f66 (plain)
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
/* -*- 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<gfx::IntRect>& 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) const {
    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);
    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 {
    if (aRect.IsEmpty()) {
      return aRect;
    }

    gfx::Rect result(IntRectToRect(aRect));
    TransformRect(result);
    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) {
    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 gfx::IntRect clipRect = *node->Clip();
        result.AndWith(clipRect);
      }

      node = node->Parent();
    }

    return result;
  }

 protected:
  /**
   * Returns the post-transform clip, if there is one.
   */
  const Maybe<gfx::IntRect>& 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 {
    const TransformClipNode* node = this;
    while (node) {
      const gfx::Matrix4x4Flagged& transform = node->Transform();
      gfx::Rect maxBounds = gfx::Rect::MaxIntRect();

      if (node->Clip()) {
        maxBounds = IntRectToRect(*node->Clip());
      }

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

 private:
  MOZ_COUNTED_DTOR(TransformClipNode)

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

}  // namespace mozilla

#endif /* MOZILLA_PAINTING_TRANSFORMCLIPNODE_H */