Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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 */