mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 02:14:43 +00:00
Bug 435293. Implement CSS transforms. r=dbaron,r+sr=roc
This commit is contained in:
parent
bed72a5865
commit
48a87265ac
@ -406,7 +406,7 @@ interface nsIDOMCSS2Properties : nsISupports
|
||||
// raises(DOMException) on setting
|
||||
};
|
||||
|
||||
[scriptable, uuid(216343fe-4e61-11dd-9843-001485f1fdbb)]
|
||||
[scriptable, uuid(06b9eb9a-a845-4cb7-a941-fa87305ded4b)]
|
||||
interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties
|
||||
{
|
||||
/* Non-DOM 2 extensions */
|
||||
@ -614,4 +614,11 @@ interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties
|
||||
|
||||
attribute DOMString wordWrap;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
attribute DOMString MozTransform;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
attribute DOMString MozTransformOrigin;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
};
|
||||
|
@ -320,7 +320,7 @@ inline PRInt32 NSToIntRound(float aValue)
|
||||
/*
|
||||
* App Unit/Pixel conversions
|
||||
*/
|
||||
inline nscoord NSFloatPixelsToAppUnits(float aPixels, PRInt32 aAppUnitsPerPixel)
|
||||
inline nscoord NSFloatPixelsToAppUnits(float aPixels, float aAppUnitsPerPixel)
|
||||
{
|
||||
float product = aPixels * aAppUnitsPerPixel;
|
||||
nscoord result;
|
||||
@ -354,12 +354,12 @@ inline nscoord NSIntPixelsToAppUnits(PRInt32 aPixels, PRInt32 aAppUnitsPerPixel)
|
||||
return r;
|
||||
}
|
||||
|
||||
inline float NSAppUnitsToFloatPixels(nscoord aAppUnits, PRInt32 aAppUnitsPerPixel)
|
||||
inline float NSAppUnitsToFloatPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
|
||||
{
|
||||
return (float(aAppUnits) / aAppUnitsPerPixel);
|
||||
}
|
||||
|
||||
inline PRInt32 NSAppUnitsToIntPixels(nscoord aAppUnits, PRInt32 aAppUnitsPerPixel)
|
||||
inline PRInt32 NSAppUnitsToIntPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
|
||||
{
|
||||
return NSToIntRound(float(aAppUnits) / aAppUnitsPerPixel);
|
||||
}
|
||||
|
@ -1076,10 +1076,12 @@ private:
|
||||
nsAbsoluteItems* mItems; // pointer to struct whose data we save/restore
|
||||
PRBool* mFirstLetterStyle;
|
||||
PRBool* mFirstLineStyle;
|
||||
PRBool* mFixedPosIsAbsPos;
|
||||
|
||||
nsAbsoluteItems mSavedItems; // copy of original data
|
||||
PRBool mSavedFirstLetterStyle;
|
||||
PRBool mSavedFirstLineStyle;
|
||||
PRBool mSavedFixedPosIsAbsPos;
|
||||
|
||||
// The name of the child list in which our frames would belong
|
||||
nsIAtom* mChildListName;
|
||||
@ -1109,6 +1111,14 @@ public:
|
||||
nsAbsoluteItems mFloatedItems;
|
||||
PRBool mFirstLetterStyle;
|
||||
PRBool mFirstLineStyle;
|
||||
|
||||
// When working with the -moz-transform property, we want to hook
|
||||
// the abs-pos and fixed-pos lists together, since transformed
|
||||
// elements are fixed-pos containing blocks. This flag determines
|
||||
// whether or not we want to wire the fixed-pos and abs-pos lists
|
||||
// together.
|
||||
PRBool mFixedPosIsAbsPos;
|
||||
|
||||
nsCOMPtr<nsILayoutHistoryState> mFrameState;
|
||||
nsPseudoFrames mPseudoFrames;
|
||||
// These bits will be added to the state bits of any frame we construct
|
||||
@ -1189,6 +1199,21 @@ public:
|
||||
PRBool aInsertAfter = PR_FALSE,
|
||||
nsIFrame* aInsertAfterFrame = nsnull);
|
||||
|
||||
/**
|
||||
* Function to return the fixed-pos element list. Normally this will just hand back the
|
||||
* fixed-pos element list, but in case we're dealing with a transformed element that's
|
||||
* acting as an abs-pos and fixed-pos container, we'll hand back the abs-pos list. Callers should
|
||||
* use this function if they want to get the list acting as the fixed-pos item parent.
|
||||
*/
|
||||
nsAbsoluteItems& GetFixedItems()
|
||||
{
|
||||
return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
|
||||
}
|
||||
const nsAbsoluteItems& GetFixedItems() const
|
||||
{
|
||||
return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class nsFrameConstructorSaveState;
|
||||
|
||||
@ -1217,6 +1242,7 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShe
|
||||
mFloatedItems(aFloatContainingBlock),
|
||||
mFirstLetterStyle(PR_FALSE),
|
||||
mFirstLineStyle(PR_FALSE),
|
||||
mFixedPosIsAbsPos(PR_FALSE),
|
||||
mFrameState(aHistoryState),
|
||||
mPseudoFrames(),
|
||||
mAdditionalStateBits(0)
|
||||
@ -1240,6 +1266,7 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
|
||||
mFloatedItems(aFloatContainingBlock),
|
||||
mFirstLetterStyle(PR_FALSE),
|
||||
mFirstLineStyle(PR_FALSE),
|
||||
mFixedPosIsAbsPos(PR_FALSE),
|
||||
mPseudoFrames(),
|
||||
mAdditionalStateBits(0)
|
||||
{
|
||||
@ -1286,8 +1313,19 @@ nsFrameConstructorState::PushAbsoluteContainingBlock(nsIFrame* aNewAbsoluteConta
|
||||
aSaveState.mSavedItems = mAbsoluteItems;
|
||||
aSaveState.mChildListName = nsGkAtoms::absoluteList;
|
||||
aSaveState.mState = this;
|
||||
|
||||
/* Store whether we're wiring the abs-pos and fixed-pos lists together. */
|
||||
aSaveState.mFixedPosIsAbsPos = &mFixedPosIsAbsPos;
|
||||
aSaveState.mSavedFixedPosIsAbsPos = mFixedPosIsAbsPos;
|
||||
|
||||
mAbsoluteItems =
|
||||
nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock));
|
||||
|
||||
/* See if we're wiring the fixed-pos and abs-pos lists together. This happens iff
|
||||
* we're a transformed element.
|
||||
*/
|
||||
mFixedPosIsAbsPos = (aNewAbsoluteContainingBlock &&
|
||||
aNewAbsoluteContainingBlock->GetStyleDisplay()->HasTransform());
|
||||
}
|
||||
|
||||
void
|
||||
@ -1350,8 +1388,8 @@ nsFrameConstructorState::GetGeometricParent(const nsStyleDisplay* aStyleDisplay,
|
||||
}
|
||||
|
||||
if (aStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED &&
|
||||
mFixedItems.containingBlock) {
|
||||
return mFixedItems.containingBlock;
|
||||
GetFixedItems().containingBlock) {
|
||||
return GetFixedItems().containingBlock;
|
||||
}
|
||||
|
||||
return aContentParentFrame;
|
||||
@ -1402,11 +1440,11 @@ nsFrameConstructorState::AddChild(nsIFrame* aNewFrame,
|
||||
frameItems = &mAbsoluteItems;
|
||||
}
|
||||
if (disp->mPosition == NS_STYLE_POSITION_FIXED &&
|
||||
mFixedItems.containingBlock) {
|
||||
NS_ASSERTION(aNewFrame->GetParent() == mFixedItems.containingBlock,
|
||||
GetFixedItems().containingBlock) {
|
||||
NS_ASSERTION(aNewFrame->GetParent() == GetFixedItems().containingBlock,
|
||||
"Fixed pos whose parent is not the fixed pos containing block?");
|
||||
needPlaceholder = PR_TRUE;
|
||||
frameItems = &mFixedItems;
|
||||
frameItems = &GetFixedItems();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1548,9 +1586,11 @@ nsFrameConstructorSaveState::nsFrameConstructorSaveState()
|
||||
: mItems(nsnull),
|
||||
mFirstLetterStyle(nsnull),
|
||||
mFirstLineStyle(nsnull),
|
||||
mFixedPosIsAbsPos(nsnull),
|
||||
mSavedItems(nsnull),
|
||||
mSavedFirstLetterStyle(PR_FALSE),
|
||||
mSavedFirstLineStyle(PR_FALSE),
|
||||
mSavedFixedPosIsAbsPos(PR_FALSE),
|
||||
mChildListName(nsnull),
|
||||
mState(nsnull)
|
||||
{
|
||||
@ -1575,6 +1615,9 @@ nsFrameConstructorSaveState::~nsFrameConstructorSaveState()
|
||||
if (mFirstLineStyle) {
|
||||
*mFirstLineStyle = mSavedFirstLineStyle;
|
||||
}
|
||||
if (mFixedPosIsAbsPos) {
|
||||
*mFixedPosIsAbsPos = mSavedFixedPosIsAbsPos;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
@ -6470,15 +6513,17 @@ nsCSSFrameConstructor::ConstructFrameByDisplayType(nsFrameConstructorState& aSta
|
||||
rv = ConstructBlock(aState, aDisplay, aContent,
|
||||
aState.GetGeometricParent(aDisplay, aParentFrame),
|
||||
aParentFrame, aStyleContext, &newFrame, aFrameItems,
|
||||
aDisplay->mPosition == NS_STYLE_POSITION_RELATIVE);
|
||||
aDisplay->mPosition == NS_STYLE_POSITION_RELATIVE ||
|
||||
aDisplay->HasTransform());
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
addedToFrameList = PR_TRUE;
|
||||
}
|
||||
// See if it's relatively positioned
|
||||
else if ((NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition) &&
|
||||
// See if it's relatively positioned or transformed
|
||||
else if ((NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition ||
|
||||
aDisplay->HasTransform()) &&
|
||||
(aDisplay->IsBlockInside() ||
|
||||
(NS_STYLE_DISPLAY_INLINE == aDisplay->mDisplay))) {
|
||||
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
|
||||
|
@ -51,6 +51,8 @@
|
||||
#include "nsFrameManager.h"
|
||||
#include "gfxContext.h"
|
||||
#include "nsStyleStructInlines.h"
|
||||
#include "nsStyleTransformMatrix.h"
|
||||
#include "gfxMatrix.h"
|
||||
#ifdef MOZ_SVG
|
||||
#include "nsSVGIntegrationUtils.h"
|
||||
#endif
|
||||
@ -370,7 +372,7 @@ nsIFrame* nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, nsPoint aPt,
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(aState->mItemBuffer.Length() == itemBufferStart,
|
||||
NS_ASSERTION(aState->mItemBuffer.Length() == PRUint32(itemBufferStart),
|
||||
"How did we forget to pop some elements?");
|
||||
return nsnull;
|
||||
}
|
||||
@ -935,6 +937,395 @@ nsDisplayWrapList* nsDisplayClip::WrapWithClone(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayClip(aItem->GetUnderlyingFrame(), mClippingFrame, aItem, mClip);
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// nsDisplayTransform Implementation
|
||||
//
|
||||
|
||||
// Write #define UNIFIED_CONTINUATIONS here to have the transform property try
|
||||
// to transform content with continuations as one unified block instead of
|
||||
// several smaller ones. This is currently disabled because it doesn't work
|
||||
// correctly, since when the frames are initially being reflown, their
|
||||
// continuations all compute their bounding rects independently of each other
|
||||
// and consequently get the wrong value. Write #define DEBUG_HIT here to have
|
||||
// the nsDisplayTransform class dump out a bunch of information about hit
|
||||
// detection.
|
||||
#undef UNIFIED_CONTINUATIONS
|
||||
#undef DEBUG_HIT
|
||||
|
||||
/* Returns the bounds of a frame as defined for transforms. If
|
||||
* UNIFIED_CONTINUATIONS is not defined, this is simply the frame's bounding
|
||||
* rectangle, translated to the origin. Otherwise, returns the smallest
|
||||
* rectangle containing a frame and all of its continuations. For example, if
|
||||
* there is a <span> element with several continuations split over several
|
||||
* lines, this function will return the rectangle containing all of those
|
||||
* continuations. This rectangle is relative to the origin of the frame's local
|
||||
* coordinate space.
|
||||
*/
|
||||
#ifndef UNIFIED_CONTINUATIONS
|
||||
|
||||
nsRect
|
||||
nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
|
||||
return nsRect(nsPoint(0, 0), aFrame->GetSize());
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
nsRect
|
||||
nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
|
||||
|
||||
nsRect result;
|
||||
|
||||
/* Iterate through the continuation list, unioning together all the
|
||||
* bounding rects.
|
||||
*/
|
||||
for (const nsIFrame *currFrame = aFrame->GetFirstContinuation();
|
||||
currFrame != nsnull;
|
||||
currFrame = currFrame->GetNextContinuation())
|
||||
{
|
||||
/* Get the frame rect in local coordinates, then translate back to the
|
||||
* original coordinates.
|
||||
*/
|
||||
result.UnionRect(result, nsRect(currFrame->GetOffsetTo(aFrame),
|
||||
currFrame->GetSize()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Returns the delta specified by the -moz-tranform-origin property.
|
||||
* This is a positive delta, meaning that it indicates the direction to move
|
||||
* to get from (0, 0) of the frame to the transform origin.
|
||||
*/
|
||||
static
|
||||
gfxPoint GetDeltaToMozTransformOrigin(const nsIFrame* aFrame,
|
||||
float aFactor,
|
||||
const nsRect* aBoundsOverride)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
|
||||
NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
|
||||
"Can't get a delta for an untransformed frame!");
|
||||
|
||||
/* For both of the coordinates, if the value of -moz-transform is a
|
||||
* percentage, it's relative to the size of the frame. Otherwise, if it's
|
||||
* a distance, it's already computed for us!
|
||||
*/
|
||||
const nsStyleDisplay* display = aFrame->GetStyleDisplay();
|
||||
nsRect boundingRect = (aBoundsOverride ? *aBoundsOverride :
|
||||
nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
|
||||
|
||||
/* Allows us to access named variables by index. */
|
||||
gfxPoint result;
|
||||
gfxFloat* coords[2] = {&result.x, &result.y};
|
||||
const nscoord* dimensions[2] =
|
||||
{&boundingRect.width, &boundingRect.height};
|
||||
|
||||
for (PRUint8 index = 0; index < 2; ++index) {
|
||||
/* If the -moz-transform-origin specifies a percentage, take the percentage
|
||||
* of the size of the box.
|
||||
*/
|
||||
if (display->mTransformOrigin[index].GetUnit() == eStyleUnit_Percent)
|
||||
*coords[index] = NSAppUnitsToFloatPixels(*dimensions[index], aFactor) *
|
||||
display->mTransformOrigin[index].GetPercentValue();
|
||||
|
||||
/* Otherwise, it's a length. */
|
||||
else
|
||||
*coords[index] =
|
||||
NSAppUnitsToFloatPixels(display->
|
||||
mTransformOrigin[index].GetCoordValue(),
|
||||
aFactor);
|
||||
}
|
||||
|
||||
/* Adjust based on the origin of the rectangle. */
|
||||
result.x += NSAppUnitsToFloatPixels(boundingRect.x, aFactor);
|
||||
result.y += NSAppUnitsToFloatPixels(boundingRect.y, aFactor);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Wraps up the -moz-transform matrix in a change-of-basis matrix pair that
|
||||
* translates from local coordinate space to transform coordinate space, then
|
||||
* hands it back.
|
||||
*/
|
||||
gfxMatrix
|
||||
nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
|
||||
const nsPoint &aOrigin,
|
||||
float aFactor,
|
||||
const nsRect* aBoundsOverride)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Cannot get transform matrix for a null frame!");
|
||||
NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
|
||||
"Cannot get transform matrix if frame isn't transformed!");
|
||||
|
||||
/* Account for the -moz-transform-origin property by translating the
|
||||
* coordinate space to the new origin.
|
||||
*/
|
||||
gfxPoint toMozOrigin = GetDeltaToMozTransformOrigin(aFrame, aFactor, aBoundsOverride);
|
||||
gfxPoint newOrigin = gfxPoint(NSAppUnitsToFloatPixels(aOrigin.x, aFactor),
|
||||
NSAppUnitsToFloatPixels(aOrigin.y, aFactor));
|
||||
|
||||
/* Get the underlying transform matrix. This requires us to get the
|
||||
* bounds of the frame.
|
||||
*/
|
||||
const nsStyleDisplay* disp = aFrame->GetStyleDisplay();
|
||||
nsRect bounds = (aBoundsOverride ? *aBoundsOverride :
|
||||
nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
|
||||
|
||||
/* Get the matrix, then change its basis to factor in the origin. */
|
||||
return nsLayoutUtils::ChangeMatrixBasis
|
||||
(newOrigin + toMozOrigin, disp->mTransform.GetThebesMatrix(bounds, aFactor));
|
||||
}
|
||||
|
||||
/* Painting applies the transform, paints the sublist, then unapplies
|
||||
* the transform.
|
||||
*/
|
||||
void nsDisplayTransform::Paint(nsDisplayListBuilder *aBuilder,
|
||||
nsIRenderingContext *aCtx,
|
||||
const nsRect &aDirtyRect)
|
||||
{
|
||||
/* Here's how this is going to work:
|
||||
* 1. Convert the stored transform matrix into a gfxMatrix
|
||||
* 2. Read out the old graphics matrix.
|
||||
* 3. Compute the net graphics matrix at this point.
|
||||
* 4. Set that as the active matrix.
|
||||
* 5. Apply the inverse transform to the dirty rect so that children think
|
||||
* they're drawing in local space.
|
||||
* 6. Render everything.
|
||||
* 7. Reset the matrix.
|
||||
*/
|
||||
/* Get the context and automatically save and restore it. */
|
||||
gfxContext* gfx = aCtx->ThebesContext();
|
||||
gfxContextAutoSaveRestore autoRestorer(gfx);
|
||||
|
||||
/* Unit conversion is based on the local presentation context. */
|
||||
float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
|
||||
/* Compute the new matrix by taking the old matrix and multiplying the
|
||||
* transform matrix of this frame only. The new transform is prepended to
|
||||
* the old transform, since that way, if we have several stacked transforms,
|
||||
* the innermost transform is applied first.
|
||||
*/
|
||||
gfxMatrix newTransformMatrix =
|
||||
GetResultingTransformMatrix(mFrame, aBuilder->ToReferenceFrame(mFrame),
|
||||
factor, nsnull);
|
||||
|
||||
newTransformMatrix.Multiply(gfx->CurrentMatrix());
|
||||
|
||||
/* Set the matrix for the transform based on the old matrix and the new
|
||||
* transform data.
|
||||
*/
|
||||
gfx->SetMatrix(newTransformMatrix);
|
||||
|
||||
/* Now, send the paint call down. As we do this, we need to be sure to
|
||||
* untransform the dirty rect, since we want everything that's painting to
|
||||
* think that it's painting in its original rectangular coordinate space.
|
||||
*/
|
||||
mStoredList.Paint(aBuilder, aCtx,
|
||||
UntransformRect(aDirtyRect, mFrame,
|
||||
aBuilder->ToReferenceFrame(mFrame)));
|
||||
|
||||
/* The AutoSaveRestore object will clean things up. */
|
||||
}
|
||||
|
||||
/* We don't need to do anything here. */
|
||||
PRBool nsDisplayTransform::OptimizeVisibility(nsDisplayListBuilder *aBuilder,
|
||||
nsRegion *aVisibleRegion)
|
||||
{
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_HIT
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
/* HitTest does some fun stuff with matrix transforms to obtain the answer. */
|
||||
nsIFrame *nsDisplayTransform::HitTest(nsDisplayListBuilder *aBuilder,
|
||||
nsPoint aPt,
|
||||
HitTestState *aState)
|
||||
{
|
||||
/* Here's how this works:
|
||||
* 1. Get the matrix. If it's singular, abort (clearly we didn't hit
|
||||
* anything).
|
||||
* 2. Invert the matrix.
|
||||
* 3. Use it to transform the point into the correct space.
|
||||
* 4. Pass that point down through to the list's version of HitTest.
|
||||
*/
|
||||
float factor = nsPresContext::AppUnitsPerCSSPixel();
|
||||
gfxMatrix matrix =
|
||||
GetResultingTransformMatrix(mFrame, aBuilder->ToReferenceFrame(mFrame),
|
||||
factor, nsnull);
|
||||
if (matrix.IsSingular())
|
||||
return nsnull;
|
||||
|
||||
/* We want to go from transformed-space to regular space.
|
||||
* Thus we have to invert the matrix, which normally does
|
||||
* the reverse operation (e.g. regular->transformed)
|
||||
*/
|
||||
matrix.Invert();
|
||||
|
||||
/* Now, apply the transform and pass it down the channel. */
|
||||
gfxPoint result = matrix.Transform(gfxPoint(NSAppUnitsToFloatPixels(aPt.x, factor),
|
||||
NSAppUnitsToFloatPixels(aPt.y, factor)));
|
||||
|
||||
#ifdef DEBUG_HIT
|
||||
printf("Frame: %p\n", dynamic_cast<void *>(mFrame));
|
||||
printf(" Untransformed point: (%f, %f)\n", result.x, result.y);
|
||||
#endif
|
||||
|
||||
nsIFrame* resultFrame =
|
||||
mStoredList.HitTest(aBuilder,
|
||||
nsPoint(NSFloatPixelsToAppUnits(float(result.x), factor),
|
||||
NSFloatPixelsToAppUnits(float(result.y), factor)), aState);
|
||||
|
||||
#ifdef DEBUG_HIT
|
||||
if (resultFrame)
|
||||
printf(" Hit! Time: %f, frame: %p\n", static_cast<double>(clock()),
|
||||
dynamic_cast<void *>(resultFrame));
|
||||
printf("=== end of hit test ===\n");
|
||||
#endif
|
||||
|
||||
return resultFrame;
|
||||
}
|
||||
|
||||
/* The bounding rectangle for the object is the overflow rectangle translated
|
||||
* by the reference point.
|
||||
*/
|
||||
nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder *aBuilder)
|
||||
{
|
||||
return mFrame->GetOverflowRect() + aBuilder->ToReferenceFrame(mFrame);
|
||||
}
|
||||
|
||||
/* The transform is opaque iff the transform consists solely of scales and
|
||||
* transforms and if the underlying content is opaque. Thus if the transform
|
||||
* is of the form
|
||||
*
|
||||
* |a c e|
|
||||
* |b d f|
|
||||
* |0 0 1|
|
||||
*
|
||||
* We need b and c to be zero.
|
||||
*/
|
||||
PRBool nsDisplayTransform::IsOpaque(nsDisplayListBuilder *aBuilder)
|
||||
{
|
||||
const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
|
||||
return disp->mTransform.GetMainMatrixEntry(1) == 0.0f &&
|
||||
disp->mTransform.GetMainMatrixEntry(2) == 0.0f &&
|
||||
mStoredList.IsOpaque(aBuilder);
|
||||
}
|
||||
|
||||
/* The transform is uniform if it fills the entire bounding rect and the
|
||||
* wrapped list is uniform. See IsOpaque for discussion of why this
|
||||
* works.
|
||||
*/
|
||||
PRBool nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder)
|
||||
{
|
||||
const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
|
||||
return disp->mTransform.GetMainMatrixEntry(1) == 0.0f &&
|
||||
disp->mTransform.GetMainMatrixEntry(2) == 0.0f &&
|
||||
mStoredList.IsUniform(aBuilder);
|
||||
}
|
||||
|
||||
/* If UNIFIED_CONTINUATIONS is defined, we can merge two display lists that
|
||||
* share the same underlying content. Otherwise, doing so results in graphical
|
||||
* glitches.
|
||||
*/
|
||||
#ifndef UNIFIED_CONTINUATIONS
|
||||
|
||||
PRBool
|
||||
nsDisplayTransform::TryMerge(nsDisplayListBuilder *aBuilder,
|
||||
nsDisplayItem *aItem)
|
||||
{
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
PRBool
|
||||
nsDisplayTransform::TryMerge(nsDisplayListBuilder *aBuilder,
|
||||
nsDisplayItem *aItem)
|
||||
{
|
||||
NS_PRECONDITION(aItem, "Why did you try merging with a null item?");
|
||||
NS_PRECONDITION(aBuilder, "Why did you try merging with a null builder?");
|
||||
|
||||
/* Make sure that we're dealing with two transforms. */
|
||||
if (aItem->GetType() != TYPE_TRANSFORM)
|
||||
return PR_FALSE;
|
||||
|
||||
/* Check to see that both frames are part of the same content. */
|
||||
if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent())
|
||||
return PR_FALSE;
|
||||
|
||||
/* Now, move everything over to this frame and signal that
|
||||
* we merged things!
|
||||
*/
|
||||
mStoredList.GetList()->
|
||||
AppendToBottom(&static_cast<nsDisplayTransform *>(aItem)->mStoredList);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* TransformRect takes in as parameters a rectangle (in app space) and returns
|
||||
* the smallest rectangle (in app space) containing the transformed image of
|
||||
* that rectangle. That is, it takes the four corners of the rectangle,
|
||||
* transforms them according to the matrix associated with the specified frame,
|
||||
* then returns the smallest rectangle containing the four transformed points.
|
||||
*
|
||||
* @param aUntransformedBounds The rectangle (in app units) to transform.
|
||||
* @param aFrame The frame whose transformation should be applied.
|
||||
* @param aOrigin The delta from the frame origin to the coordinate space origin
|
||||
* @param aBoundsOverride (optional) Force the frame bounds to be the
|
||||
* specified bounds.
|
||||
* @return The smallest rectangle containing the image of the transformed
|
||||
* rectangle.
|
||||
*/
|
||||
nsRect nsDisplayTransform::TransformRect(const nsRect &aUntransformedBounds,
|
||||
const nsIFrame* aFrame,
|
||||
const nsPoint &aOrigin,
|
||||
const nsRect* aBoundsOverride)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
|
||||
NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
|
||||
"Cannot transform a rectangle if there's no transformation!");
|
||||
|
||||
float factor = nsPresContext::AppUnitsPerCSSPixel();
|
||||
return nsLayoutUtils::MatrixTransformRect
|
||||
(aUntransformedBounds,
|
||||
GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride),
|
||||
factor);
|
||||
}
|
||||
|
||||
nsRect nsDisplayTransform::UntransformRect(const nsRect &aUntransformedBounds,
|
||||
const nsIFrame* aFrame,
|
||||
const nsPoint &aOrigin)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
|
||||
NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
|
||||
"Cannot transform a rectangle if there's no transformation!");
|
||||
|
||||
|
||||
/* Grab the matrix. If the transform is degenerate, just hand back the
|
||||
* empty rect.
|
||||
*/
|
||||
float factor = nsPresContext::AppUnitsPerCSSPixel();
|
||||
gfxMatrix matrix = GetResultingTransformMatrix(aFrame, aOrigin, factor, nsnull);
|
||||
if (matrix.IsSingular())
|
||||
return nsRect();
|
||||
|
||||
/* We want to untransform the matrix, so invert the transformation first! */
|
||||
matrix.Invert();
|
||||
|
||||
return nsLayoutUtils::MatrixTransformRect(aUntransformedBounds, matrix,
|
||||
factor);
|
||||
}
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
nsDisplaySVGEffects::nsDisplaySVGEffects(nsIFrame* aFrame, nsDisplayList* aList)
|
||||
: nsDisplayWrapList(aFrame, aList), mEffectsFrame(aFrame),
|
||||
|
@ -53,7 +53,6 @@
|
||||
#include "nsCaret.h"
|
||||
#include "plarena.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -207,7 +206,7 @@ public:
|
||||
* aFrame->GetOffsetTo(ReferenceFrame()). It may be optimized to be faster
|
||||
* than aFrame->GetOffsetTo(ReferenceFrame()) (but currently isn't).
|
||||
*/
|
||||
nsPoint ToReferenceFrame(nsIFrame* aFrame) {
|
||||
nsPoint ToReferenceFrame(const nsIFrame* aFrame) {
|
||||
return aFrame->GetOffsetTo(ReferenceFrame());
|
||||
}
|
||||
/**
|
||||
@ -395,7 +394,8 @@ public:
|
||||
#ifdef MOZ_SVG
|
||||
TYPE_SVG_EFFECTS,
|
||||
#endif
|
||||
TYPE_WRAPLIST
|
||||
TYPE_WRAPLIST,
|
||||
TYPE_TRANSFORM
|
||||
};
|
||||
|
||||
struct HitTestState {
|
||||
@ -1294,4 +1294,115 @@ private:
|
||||
};
|
||||
#endif
|
||||
|
||||
/* A display item that applies a transformation to all of its descendent
|
||||
* elements. This wrapper should only be used if there is a transform applied
|
||||
* to the root element.
|
||||
* INVARIANT: The wrapped frame is transformed.
|
||||
* INVARIANT: The wrapped frame is non-null.
|
||||
*/
|
||||
class nsDisplayTransform: public nsDisplayItem
|
||||
{
|
||||
public:
|
||||
/* Constructor accepts a display list, empties it, and wraps it up. It also
|
||||
* ferries the underlying frame to the nsDisplayItem constructor.
|
||||
*/
|
||||
nsDisplayTransform(nsIFrame *aFrame, nsDisplayList *aList) :
|
||||
nsDisplayItem(aFrame), mStoredList(aFrame, aList)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsDisplayTransform);
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayTransform()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsDisplayTransform);
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_DISPLAY_DECL_NAME("nsDisplayTransform");
|
||||
|
||||
virtual Type GetType()
|
||||
{
|
||||
return TYPE_TRANSFORM;
|
||||
}
|
||||
|
||||
virtual nsIFrame* HitTest(nsDisplayListBuilder *aBuilder, nsPoint aPt,
|
||||
HitTestState *aState);
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder *aBuilder);
|
||||
virtual PRBool IsOpaque(nsDisplayListBuilder *aBuilder);
|
||||
virtual PRBool IsUniform(nsDisplayListBuilder *aBuilder);
|
||||
virtual void Paint(nsDisplayListBuilder *aBuilder,
|
||||
nsIRenderingContext *aCtx,
|
||||
const nsRect &aDirtyRect);
|
||||
virtual PRBool OptimizeVisibility(nsDisplayListBuilder *aBuilder,
|
||||
nsRegion *aVisibleRegion);
|
||||
virtual PRBool TryMerge(nsDisplayListBuilder *aBuilder, nsDisplayItem *aItem);
|
||||
|
||||
/**
|
||||
* TransformRect takes in as parameters a rectangle (in aFrame's coordinate
|
||||
* space) and returns the smallest rectangle (in aFrame's coordinate space)
|
||||
* containing the transformed image of that rectangle. That is, it takes
|
||||
* the four corners of the rectangle, transforms them according to the
|
||||
* matrix associated with the specified frame, then returns the smallest
|
||||
* rectangle containing the four transformed points.
|
||||
*
|
||||
* @param untransformedBounds The rectangle (in app units) to transform.
|
||||
* @param aFrame The frame whose transformation should be applied. This
|
||||
* function raises an assertion if aFrame is null or doesn't have a
|
||||
* transform applied to it.
|
||||
* @param aOrigin The origin of the transform relative to aFrame's local
|
||||
* coordinate space.
|
||||
* @param aBoundsOverride (optional) Rather than using the frame's computed
|
||||
* bounding rect as frame bounds, use this rectangle instead. Pass
|
||||
* nsnull (or nothing at all) to use the default.
|
||||
*/
|
||||
static nsRect TransformRect(const nsRect &aUntransformedBounds,
|
||||
const nsIFrame* aFrame,
|
||||
const nsPoint &aOrigin,
|
||||
const nsRect* aBoundsOverride = nsnull);
|
||||
|
||||
/* UntransformRect is like TransformRect, except that it inverts the
|
||||
* transform.
|
||||
*/
|
||||
static nsRect UntransformRect(const nsRect &aUntransformedBounds,
|
||||
const nsIFrame* aFrame,
|
||||
const nsPoint &aOrigin);
|
||||
|
||||
/**
|
||||
* Returns the bounds of a frame as defined for transforms. If
|
||||
* UNIFIED_CONTINUATIONS is not defined, this is simply the frame's bounding
|
||||
* rectangle, translated to the origin. Otherwise, returns the smallest
|
||||
* rectangle containing a frame and all of its continuations. For example,
|
||||
* if there is a <span> element with several continuations split over
|
||||
* several lines, this function will return the rectangle containing all of
|
||||
* those continuations. This rectangle is relative to the origin of the
|
||||
* frame's local coordinate space.
|
||||
*
|
||||
* @param aFrame The frame to get the bounding rect for.
|
||||
* @return The frame's bounding rect, as described above.
|
||||
*/
|
||||
static nsRect GetFrameBoundsForTransform(const nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Given a frame with the -moz-transform property, returns the
|
||||
* transformation matrix for that frame.
|
||||
*
|
||||
* @param aFrame The frame to get the matrix from.
|
||||
* @param aOrigin Relative to which point this transform should be applied.
|
||||
* @param aScaleFactor The number of app units per graphics unit.
|
||||
* @param aBoundsOverride [optional] If this is nsnull (the default), the
|
||||
* computation will use the value of GetFrameBoundsForTransform(aFrame)
|
||||
* for the frame's bounding rectangle. Otherwise, it will use the
|
||||
* value of aBoundsOverride. This is mostly for internal use and in
|
||||
* most cases you will not need to specify a value.
|
||||
*/
|
||||
static gfxMatrix GetResultingTransformMatrix(const nsIFrame* aFrame,
|
||||
const nsPoint& aOrigin,
|
||||
float aFactor,
|
||||
const nsRect* aBoundsOverride = nsnull);
|
||||
|
||||
private:
|
||||
nsDisplayWrapList mStoredList;
|
||||
};
|
||||
|
||||
#endif /*NSDISPLAYLIST_H_*/
|
||||
|
@ -76,6 +76,8 @@
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfxTypes.h"
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
#include "nsSVGUtils.h"
|
||||
@ -639,19 +641,17 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent, nsIFrame* aF
|
||||
if (!GUIEvent->widget)
|
||||
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
|
||||
// If it is, or is a descendant of, an SVG foreignobject frame,
|
||||
// then we need to do extra work
|
||||
/* If we walk up the frame tree and discover that any of the frames are
|
||||
* transformed, we need to do extra work to convert from the global
|
||||
* space to the local space.
|
||||
*/
|
||||
nsIFrame* rootFrame = aFrame;
|
||||
PRBool transformFound = PR_FALSE;
|
||||
|
||||
for (nsIFrame* f = aFrame; f; f = GetCrossDocParentFrame(f)) {
|
||||
#ifdef MOZ_SVG
|
||||
if (f->IsFrameOfType(nsIFrame::eSVGForeignObject) && f->GetFirstChild(nsnull)) {
|
||||
nsSVGForeignObjectFrame* fo = static_cast<nsSVGForeignObjectFrame*>(f);
|
||||
nsIFrame* outer = nsSVGUtils::GetOuterSVGFrame(fo);
|
||||
return fo->TransformPointFromOuter(
|
||||
GetEventCoordinatesRelativeTo(aEvent, outer)) -
|
||||
aFrame->GetOffsetTo(fo->GetFirstChild(nsnull));
|
||||
}
|
||||
#endif
|
||||
if (f->IsTransformed())
|
||||
transformFound = PR_TRUE;
|
||||
|
||||
rootFrame = f;
|
||||
}
|
||||
|
||||
@ -666,9 +666,134 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent, nsIFrame* aF
|
||||
if (widgetToView == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE))
|
||||
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
|
||||
/* If we encountered a transform, we can't do simple arithmetic to figure
|
||||
* out how to convert back to aFrame's coordinates and must use the CTM.
|
||||
*/
|
||||
if (transformFound)
|
||||
return InvertTransformsToRoot(aFrame, widgetToView);
|
||||
|
||||
/* Otherwise, all coordinate systems are translations of one another,
|
||||
* so we can just subtract out the different.
|
||||
*/
|
||||
return widgetToView - aFrame->GetOffsetTo(rootFrame);
|
||||
}
|
||||
|
||||
gfxMatrix
|
||||
nsLayoutUtils::ChangeMatrixBasis(const gfxPoint &aOrigin,
|
||||
const gfxMatrix &aMatrix)
|
||||
{
|
||||
/* These are translation matrices from world-to-origin of relative frame and
|
||||
* vice-versa. Although I could use the gfxMatrix::Translate function to
|
||||
* accomplish this, I'm hoping to reduce the overall number of matrix
|
||||
* operations by hardcoding as many of the matrices as possible.
|
||||
*/
|
||||
gfxMatrix worldToOrigin(1.0, 0.0, 0.0, 1.0, -aOrigin.x, -aOrigin.y);
|
||||
gfxMatrix originToWorld(1.0, 0.0, 0.0, 1.0, aOrigin.x, aOrigin.y);
|
||||
|
||||
/* Multiply all three to get the transform! */
|
||||
gfxMatrix result(worldToOrigin);
|
||||
result.Multiply(aMatrix);
|
||||
result.Multiply(originToWorld);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a gfxFloat, constrains its value to be between nscoord_MIN and nscoord_MAX.
|
||||
*
|
||||
* @param aVal The value to constrain (in/out)
|
||||
*/
|
||||
static void ConstrainToCoordValues(gfxFloat &aVal)
|
||||
{
|
||||
if (aVal <= nscoord_MIN)
|
||||
aVal = nscoord_MIN;
|
||||
else if (aVal >= nscoord_MAX)
|
||||
aVal = nscoord_MAX;
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsLayoutUtils::RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor)
|
||||
{
|
||||
/* Get a new gfxRect whose units are app units by scaling by the specified factor. */
|
||||
gfxRect scaledRect(aRect.pos.x * aFactor, aRect.pos.y * aFactor,
|
||||
aRect.size.width * aFactor,
|
||||
aRect.size.height * aFactor);
|
||||
|
||||
/* Round outward. */
|
||||
scaledRect.RoundOut();
|
||||
|
||||
/* We now need to constrain our results to the max and min values for coords. */
|
||||
ConstrainToCoordValues(scaledRect.pos.x);
|
||||
ConstrainToCoordValues(scaledRect.pos.y);
|
||||
ConstrainToCoordValues(scaledRect.size.width);
|
||||
ConstrainToCoordValues(scaledRect.size.height);
|
||||
|
||||
/* Now typecast everything back. This is guaranteed to be safe. */
|
||||
return nsRect(nscoord(scaledRect.pos.x), nscoord(scaledRect.pos.y),
|
||||
nscoord(scaledRect.size.width), nscoord(scaledRect.size.height));
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsLayoutUtils::MatrixTransformRect(const nsRect &aBounds,
|
||||
const gfxMatrix &aMatrix, float aFactor)
|
||||
{
|
||||
gfxRect image = aMatrix.TransformBounds(gfxRect(NSAppUnitsToFloatPixels(aBounds.x, aFactor),
|
||||
NSAppUnitsToFloatPixels(aBounds.y, aFactor),
|
||||
NSAppUnitsToFloatPixels(aBounds.width, aFactor),
|
||||
NSAppUnitsToFloatPixels(aBounds.height, aFactor)));
|
||||
|
||||
return RoundGfxRectToAppRect(image, aFactor);
|
||||
}
|
||||
|
||||
nsPoint
|
||||
nsLayoutUtils::MatrixTransformPoint(const nsPoint &aPoint,
|
||||
const gfxMatrix &aMatrix, float aFactor)
|
||||
{
|
||||
gfxPoint image = aMatrix.Transform(gfxPoint(NSAppUnitsToFloatPixels(aPoint.x, aFactor),
|
||||
NSAppUnitsToFloatPixels(aPoint.y, aFactor)));
|
||||
return nsPoint(NSFloatPixelsToAppUnits(float(image.x), aFactor),
|
||||
NSFloatPixelsToAppUnits(float(image.y), aFactor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CTM at the specified frame.
|
||||
*
|
||||
* @param aFrame The frame at which we should calculate the CTM.
|
||||
* @return The CTM at the specified frame.
|
||||
*/
|
||||
static gfxMatrix GetCTMAt(nsIFrame *aFrame)
|
||||
{
|
||||
gfxMatrix ctm;
|
||||
|
||||
/* Starting at the specified frame, we'll use the GetTransformMatrix
|
||||
* function of the frame, which gives us a matrix from this frame up
|
||||
* to some other ancestor frame. Once this function returns null,
|
||||
* we've hit the top of the frame tree and can stop. We get the CTM
|
||||
* by simply accumulating all of these matrices together.
|
||||
*/
|
||||
while (aFrame)
|
||||
ctm *= aFrame->GetTransformMatrix(&aFrame);
|
||||
return ctm;
|
||||
}
|
||||
|
||||
nsPoint
|
||||
nsLayoutUtils::InvertTransformsToRoot(nsIFrame *aFrame,
|
||||
const nsPoint &aPoint)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Why are you inverting transforms when there is no frame?");
|
||||
|
||||
/* To invert everything to the root, we'll get the CTM, invert it, and use it to transform
|
||||
* the point.
|
||||
*/
|
||||
gfxMatrix ctm = GetCTMAt(aFrame);
|
||||
|
||||
/* If the ctm is singular, hand back (0, 0) as a sentinel. */
|
||||
if (ctm.IsSingular())
|
||||
return nsPoint(0, 0);
|
||||
|
||||
/* Otherwise, invert the CTM and use it to transform the point. */
|
||||
return MatrixTransformPoint(aPoint, ctm.Invert(), aFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
}
|
||||
|
||||
nsPoint
|
||||
nsLayoutUtils::GetEventCoordinatesForNearestView(nsEvent* aEvent,
|
||||
nsIFrame* aFrame,
|
||||
|
@ -386,6 +386,20 @@ public:
|
||||
nsIWidget* aWidget, nsIntPoint aPt,
|
||||
nsIView* aView);
|
||||
|
||||
/**
|
||||
* Given a matrix and a point, let T be the transformation matrix translating points
|
||||
* in the coordinate space with origin aOrigin to the coordinate space used by the
|
||||
* matrix. If M is the stored matrix, this function returns (T-1)MT, the matrix
|
||||
* that's equivalent to aMatrix but in the coordinate space that treats aOrigin
|
||||
* as the origin.
|
||||
*
|
||||
* @param aOrigin The origin to translate to.
|
||||
* @param aMatrix The matrix to change the basis of.
|
||||
* @return A matrix equivalent to aMatrix, but operating in the coordinate system with
|
||||
* origin aOrigin.
|
||||
*/
|
||||
static gfxMatrix ChangeMatrixBasis(const gfxPoint &aOrigin, const gfxMatrix &aMatrix);
|
||||
|
||||
/**
|
||||
* Given aFrame, the root frame of a stacking context, find its descendant
|
||||
* frame under the point aPt that receives a mouse event at that location,
|
||||
@ -397,6 +411,54 @@ public:
|
||||
static nsIFrame* GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt,
|
||||
PRBool aShouldIgnoreSuppression = PR_FALSE);
|
||||
|
||||
/**
|
||||
* Given a point in the global coordinate space, returns that point expressed
|
||||
* in the coordinate system of aFrame. This effectively inverts all transforms
|
||||
* between this point and the root frame.
|
||||
*
|
||||
* @param aFrame The frame that acts as the coordinate space container.
|
||||
* @param aPoint The point, in the global space, to get in the frame-local space.
|
||||
* @return aPoint, expressed in aFrame's canonical coordinate space.
|
||||
*/
|
||||
static nsPoint InvertTransformsToRoot(nsIFrame* aFrame,
|
||||
const nsPoint &aPt);
|
||||
|
||||
|
||||
/**
|
||||
* Helper function that, given a rectangle and a matrix, returns the smallest
|
||||
* rectangle containing the image of the source rectangle.
|
||||
*
|
||||
* @param aBounds The rectangle to transform.
|
||||
* @param aMatrix The matrix to transform it with.
|
||||
* @param aFactor The number of app units per graphics unit.
|
||||
* @return The smallest rect that contains the image of aBounds.
|
||||
*/
|
||||
static nsRect MatrixTransformRect(const nsRect &aBounds,
|
||||
const gfxMatrix &aMatrix, float aFactor);
|
||||
|
||||
/**
|
||||
* Helper function that, given a point and a matrix, returns the image
|
||||
* of that point under the matrix transform.
|
||||
*
|
||||
* @param aPoint The point to transform.
|
||||
* @param aMatrix The matrix to transform it with.
|
||||
* @param aFactor The number of app units per graphics unit.
|
||||
* @return The image of the point under the transform.
|
||||
*/
|
||||
static nsPoint MatrixTransformPoint(const nsPoint &aPoint,
|
||||
const gfxMatrix &aMatrix, float aFactor);
|
||||
|
||||
/**
|
||||
* Given a graphics rectangle in graphics space, return a rectangle in
|
||||
* app space that contains the graphics rectangle, rounding out as necessary.
|
||||
*
|
||||
* @param aRect The graphics rect to round outward.
|
||||
* @param aFactor The number of app units per graphics unit.
|
||||
* @return The smallest rectangle in app space that contains aRect.
|
||||
*/
|
||||
static nsRect RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor);
|
||||
|
||||
|
||||
/**
|
||||
* Given aFrame, the root frame of a stacking context, paint it and its
|
||||
* descendants to aRenderingContext.
|
||||
|
@ -913,6 +913,7 @@ public:
|
||||
NS_IMETHOD ResizeReflow(nsIView *aView, nscoord aWidth, nscoord aHeight);
|
||||
NS_IMETHOD_(PRBool) IsVisible();
|
||||
NS_IMETHOD_(void) WillPaint();
|
||||
NS_IMETHOD_(void) InvalidateFrameForView(nsIView *view);
|
||||
|
||||
// caret handling
|
||||
NS_IMETHOD GetCaret(nsCaret **aOutCaret);
|
||||
@ -1011,7 +1012,6 @@ protected:
|
||||
|
||||
void UnsuppressAndInvalidate();
|
||||
|
||||
|
||||
void WillCauseReflow() {
|
||||
nsContentUtils::AddScriptBlocker();
|
||||
++mChangeNestCount;
|
||||
@ -2610,7 +2610,7 @@ PresShell::CreateResizeEventTimer ()
|
||||
void
|
||||
PresShell::KillResizeEventTimer()
|
||||
{
|
||||
if(mResizeEventTimer) {
|
||||
if (mResizeEventTimer) {
|
||||
mResizeEventTimer->Cancel();
|
||||
mResizeEventTimer = nsnull;
|
||||
}
|
||||
@ -4013,12 +4013,12 @@ PresShell::ScrollContentIntoView(nsIContent* aContent,
|
||||
// this check is preventing.
|
||||
// XXX: The dependency on the command dispatcher needs to be fixed.
|
||||
nsPIDOMWindow* ourWindow = currentDoc->GetWindow();
|
||||
if(ourWindow) {
|
||||
if (ourWindow) {
|
||||
nsIFocusController *focusController = ourWindow->GetRootFocusController();
|
||||
if (focusController) {
|
||||
PRBool dontScroll = PR_FALSE;
|
||||
focusController->GetSuppressFocusScroll(&dontScroll);
|
||||
if(dontScroll) {
|
||||
if (dontScroll) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@ -4191,6 +4191,14 @@ PresShell::GetSelectionForCopy(nsISelection** outSelection)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Just hook this call into InvalidateOverflowRect */
|
||||
void
|
||||
PresShell::InvalidateFrameForView(nsIView *aView)
|
||||
{
|
||||
nsIFrame* frame = nsLayoutUtils::GetFrameFor(aView);
|
||||
if (frame)
|
||||
frame->InvalidateOverflowRect();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::DoGetContents(const nsACString& aMimeType, PRUint32 aFlags, PRBool aSelectionOnly, nsAString& aOutValue)
|
||||
|
@ -560,6 +560,12 @@ nsContainerFrame::SyncFrameViewProperties(nsPresContext* aPresContext,
|
||||
}
|
||||
|
||||
nsIViewManager* vm = aView->GetViewManager();
|
||||
|
||||
/* If this frame has a -moz-transform property, tell it to invalidate on a scroll
|
||||
* rather than doing a BitBlt.
|
||||
*/
|
||||
if (aFrame->GetStyleDisplay()->HasTransform())
|
||||
aView->SetInvalidateFrameOnScroll();
|
||||
|
||||
if (nsnull == aStyleContext) {
|
||||
aStyleContext = aFrame->GetStyleContext();
|
||||
@ -633,7 +639,7 @@ nsContainerFrame::FrameNeedsView(nsIFrame* aFrame)
|
||||
nsCSSAnonBoxes::scrolledContent) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
return aFrame->NeedsView();
|
||||
return aFrame->NeedsView() || aFrame->GetStyleDisplay()->HasTransform();
|
||||
}
|
||||
|
||||
static nscoord GetCoord(const nsStyleCoord& aCoord, nscoord aIfNotCoord)
|
||||
|
@ -439,6 +439,12 @@ nsFrame::Init(nsIContent* aContent,
|
||||
mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
|
||||
NS_FRAME_GENERATED_CONTENT);
|
||||
}
|
||||
if (GetStyleDisplay()->HasTransform()) {
|
||||
// The frame gets reconstructed if we toggle the -moz-transform
|
||||
// property, so we can set this bit here and then ignore it.
|
||||
mState |= NS_FRAME_MAY_BE_TRANSFORMED;
|
||||
}
|
||||
|
||||
DidSetStyleContext();
|
||||
|
||||
if (IsBoxWrapped())
|
||||
@ -666,6 +672,13 @@ nsIFrame::GetPaddingRect() const
|
||||
return r;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsIFrame::IsTransformed() const
|
||||
{
|
||||
return (mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
|
||||
GetStyleDisplay()->HasTransform();
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsIFrame::GetContentRect() const
|
||||
{
|
||||
@ -1181,6 +1194,13 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
PRBool applyAbsPosClipping =
|
||||
ApplyAbsPosClipping(aBuilder, disp, this, &absPosClip);
|
||||
nsRect dirtyRect = aDirtyRect;
|
||||
|
||||
/* If we're being transformed, we need to invert the matrix transform so that we don't
|
||||
* grab points in the wrong coordinate system!
|
||||
*/
|
||||
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) && disp->HasTransform())
|
||||
dirtyRect = nsDisplayTransform::UntransformRect(dirtyRect, this, nsPoint(0, 0));
|
||||
|
||||
if (applyAbsPosClipping) {
|
||||
dirtyRect.IntersectRect(dirtyRect,
|
||||
absPosClip - aBuilder->ToReferenceFrame(this));
|
||||
@ -1275,16 +1295,38 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
/* If there are any SVG effects, wrap up the list in an effects list. */
|
||||
if (usingSVGEffects) {
|
||||
rv = aList->AppendNewToTop(new (aBuilder) nsDisplaySVGEffects(this, &resultList));
|
||||
nsDisplaySVGEffects* svgList = new (aBuilder) nsDisplaySVGEffects(this, &resultList);
|
||||
if (!svgList)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
/* List now emptied, so add the new list to the top. */
|
||||
resultList.AppendToTop(svgList);
|
||||
} else
|
||||
#endif
|
||||
|
||||
/* If there is any opacity, wrap it up in an opacity list. */
|
||||
if (disp->mOpacity < 1.0f) {
|
||||
rv = aList->AppendNewToTop(new (aBuilder) nsDisplayOpacity(this, &resultList));
|
||||
} else {
|
||||
aList->AppendToTop(&resultList);
|
||||
nsDisplayOpacity* opacityList = new (aBuilder) nsDisplayOpacity(this, &resultList);
|
||||
if (!opacityList)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
resultList.AppendToTop(opacityList);
|
||||
}
|
||||
|
||||
/* If we're going to apply a transformation, wrap everything in an
|
||||
* nsDisplayTransform.
|
||||
*/
|
||||
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) && disp->HasTransform()) {
|
||||
nsDisplayTransform* transform = new (aBuilder) nsDisplayTransform(this, &resultList);
|
||||
if (!transform)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
resultList.AppendToTop(transform);
|
||||
}
|
||||
|
||||
aList->AppendToTop(&resultList);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1423,7 +1465,11 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
!PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance))
|
||||
return NS_OK;
|
||||
|
||||
PRBool isComposited = disp->mOpacity != 1.0f
|
||||
// Child is composited if it's transformed, partially transparent, or has
|
||||
// SVG effects.
|
||||
PRBool isComposited = disp->mOpacity != 1.0f ||
|
||||
((aChild->mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
|
||||
aChild->GetStyleDisplay()->HasTransform())
|
||||
#ifdef MOZ_SVG
|
||||
|| nsSVGIntegrationUtils::UsingEffectsForFrame(aChild)
|
||||
#endif
|
||||
@ -3608,6 +3654,51 @@ nsIFrame::Invalidate(const nsRect& aDamageRect,
|
||||
InvalidateInternal(aDamageRect, 0, 0, nsnull, aImmediate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that funnels an InvalidateInternal request up to the
|
||||
* parent. This function is used so that if MOZ_SVG is not defined, we still
|
||||
* have unified control paths in the InvalidateInternal chain.
|
||||
*
|
||||
* @param aDamageRect The rect to invalidate.
|
||||
* @param aX The x offset from the origin of this frame to the rectangle.
|
||||
* @param aY The y offset from the origin of this frame to the rectangle.
|
||||
* @param aImmediate Whether to redraw immediately.
|
||||
* @return None, though this funnels the request up to the parent frame.
|
||||
*/
|
||||
void
|
||||
nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
|
||||
nscoord aY, PRBool aImmediate)
|
||||
{
|
||||
/* If we're a transformed frame, then we need to apply our transform to the
|
||||
* damage rectangle so that the redraw correctly redraws the transformed
|
||||
* region. We're moved over aX and aY from our origin, but since this aX
|
||||
* and aY is contained within our border, we need to scoot back by -aX and
|
||||
* -aY to get back to the origin of the transform.
|
||||
*
|
||||
* There's one more problem, though, and that's that we don't know what
|
||||
* coordinate space this rectangle is in. Sometimes it's in the local
|
||||
* coordinate space for the frame, and sometimes its in the transformed
|
||||
* coordinate space. If we get it wrong, we'll display incorrectly. Until I
|
||||
* find a better fix for this problem, we'll invalidate the union of the two
|
||||
* rectangles (original rectangle and transformed rectangle). At least one of
|
||||
* these will be correct.
|
||||
*
|
||||
* See bug #452496 for more details.
|
||||
*/
|
||||
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
|
||||
GetStyleDisplay()->HasTransform()) {
|
||||
nsRect newDamageRect;
|
||||
newDamageRect.UnionRect(nsDisplayTransform::TransformRect
|
||||
(aDamageRect, this, nsPoint(-aX, -aY)), aDamageRect);
|
||||
GetParent()->
|
||||
InvalidateInternal(newDamageRect, aX + mRect.x, aY + mRect.y, this,
|
||||
aImmediate);
|
||||
}
|
||||
else
|
||||
GetParent()->
|
||||
InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aImmediate);
|
||||
}
|
||||
|
||||
void
|
||||
nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
|
||||
nsIFrame* aForChild, PRBool aImmediate)
|
||||
@ -3616,13 +3707,81 @@ nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
|
||||
if (nsSVGIntegrationUtils::UsingEffectsForFrame(this)) {
|
||||
nsRect r = nsSVGIntegrationUtils::GetInvalidAreaForChangedSource(this,
|
||||
aDamageRect + nsPoint(aX, aY));
|
||||
GetParent()->InvalidateInternal(r, mRect.x, mRect.y, this, aImmediate);
|
||||
/* Rectangle is now in our own local space, so aX and aY are effectively
|
||||
* zero. Thus we'll pretend that the entire time this was in our own
|
||||
* local coordinate space and do any remaining processing.
|
||||
*/
|
||||
InvalidateInternalAfterResize(r, 0, 0, aImmediate);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
InvalidateInternalAfterResize(aDamageRect, aX, aY, aImmediate);
|
||||
}
|
||||
|
||||
GetParent()->
|
||||
InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aImmediate);
|
||||
gfxMatrix
|
||||
nsIFrame::GetTransformMatrix(nsIFrame **aOutAncestor)
|
||||
{
|
||||
NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
|
||||
|
||||
/* Whether or not we're transformed, the matrix will be relative to our
|
||||
* cross-doc parent frame.
|
||||
*/
|
||||
*aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
|
||||
|
||||
/* If we're transformed, we want to hand back the combination
|
||||
* transform/translate matrix that will apply our current transform, then
|
||||
* shift us to our parent.
|
||||
*/
|
||||
if (IsTransformed()) {
|
||||
/* Compute the delta to the parent, which we need because we are converting
|
||||
* coordinates to our parent.
|
||||
*/
|
||||
NS_ASSERTION(*aOutAncestor, "Cannot transform the viewport frame!");
|
||||
nsPoint delta = GetOffsetTo(*aOutAncestor);
|
||||
PRInt32 scaleFactor = PresContext()->AppUnitsPerDevPixel();
|
||||
|
||||
gfxMatrix result =
|
||||
nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0, 0),
|
||||
scaleFactor);
|
||||
/* Combine the raw transform with a translation to our parent. */
|
||||
result *= gfxMatrix().Translate
|
||||
(gfxPoint(NSAppUnitsToFloatPixels(delta.x, scaleFactor),
|
||||
NSAppUnitsToFloatPixels(delta.y, scaleFactor)));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Otherwise, we're not transformed. In that case, we'll walk up the frame
|
||||
* tree until we either hit the root frame or something that may be
|
||||
* transformed. We'll then change coordinates into that frame, since we're
|
||||
* guaranteed that nothing in-between can be transformed. First, however,
|
||||
* we have to check to see if we have a parent. If not, we'll set the
|
||||
* outparam to null (indicating that there's nothing left) and will hand back
|
||||
* the identity matrix.
|
||||
*/
|
||||
if (!*aOutAncestor)
|
||||
return gfxMatrix();
|
||||
|
||||
/* Keep iterating while the frame can't possibly be transformed. */
|
||||
while (!((*aOutAncestor)->mState & NS_FRAME_MAY_BE_TRANSFORMED)) {
|
||||
/* If no parent, stop iterating. Otherwise, update the ancestor. */
|
||||
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
|
||||
if (!parent)
|
||||
break;
|
||||
|
||||
*aOutAncestor = parent;
|
||||
}
|
||||
|
||||
NS_ASSERTION(*aOutAncestor, "Somehow ended up with a null ancestor...?");
|
||||
|
||||
/* Translate from this frame to our ancestor, if it exists. That's the
|
||||
* entire transform, so we're done.
|
||||
*/
|
||||
nsPoint delta = GetOffsetTo(*aOutAncestor);
|
||||
PRInt32 scaleFactor = PresContext()->AppUnitsPerDevPixel();
|
||||
return gfxMatrix().Translate
|
||||
(gfxPoint(NSAppUnitsToFloatPixels(delta.x, scaleFactor),
|
||||
NSAppUnitsToFloatPixels(delta.y, scaleFactor)));
|
||||
}
|
||||
|
||||
void
|
||||
@ -5439,6 +5598,17 @@ nsIFrame::FinishAndStoreOverflow(nsRect* aOverflowArea, nsSize aNewSize)
|
||||
aOverflowArea->UnionRectIncludeEmpty(*aOverflowArea,
|
||||
nsRect(nsPoint(0, 0), aNewSize));
|
||||
|
||||
/* If we're transformed, transform the overflow rect by the current transformation. */
|
||||
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
|
||||
GetStyleDisplay()->HasTransform()) {
|
||||
/* Since our size might not actually have been computed yet, we need to make sure that we use the
|
||||
* correct dimensions by overriding the stored bounding rectangle with the value the caller has
|
||||
* ensured us we'll use.
|
||||
*/
|
||||
nsRect newBounds(nsPoint(0, 0), aNewSize);
|
||||
*aOverflowArea = nsDisplayTransform::TransformRect(*aOverflowArea, this, nsPoint(0, 0), &newBounds);
|
||||
}
|
||||
|
||||
PRBool geometricOverflow =
|
||||
aOverflowArea->x < 0 || aOverflowArea->y < 0 ||
|
||||
aOverflowArea->XMost() > aNewSize.width || aOverflowArea->YMost() > aNewSize.height;
|
||||
|
@ -1391,9 +1391,16 @@ PRBool
|
||||
nsGfxScrollFrameInner::NeedsClipWidget() const
|
||||
{
|
||||
// Scrollports contained in form controls (e.g., listboxes) don't get
|
||||
// widgets.
|
||||
// widgets. Also, transformed elements don't need clip widgets since they
|
||||
// result in graphical glitches.
|
||||
for (nsIFrame* parentFrame = mOuter; parentFrame;
|
||||
parentFrame = parentFrame->GetParent()) {
|
||||
parentFrame = nsLayoutUtils::GetCrossDocParentFrame(parentFrame)) {
|
||||
|
||||
/* See if we have a transform... we should have no widget if that's the case. */
|
||||
if (parentFrame->GetStyleDisplay()->HasTransform())
|
||||
return PR_FALSE;
|
||||
|
||||
/* If we're a form element, we don't need a widget. */
|
||||
nsIFormControlFrame* fcFrame;
|
||||
if ((NS_SUCCEEDED(parentFrame->QueryInterface(NS_GET_IID(nsIFormControlFrame), (void**)&fcFrame)))) {
|
||||
return PR_FALSE;
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsHTMLReflowMetrics.h"
|
||||
#include "gfxMatrix.h"
|
||||
|
||||
/**
|
||||
* New rules of reflow:
|
||||
@ -231,7 +232,11 @@ enum {
|
||||
// results when an inline has been split because of a nested block.
|
||||
NS_FRAME_IS_SPECIAL = 0x00008000,
|
||||
|
||||
NS_FRAME_THIS_BIT_BELONGS_TO_ROC_DO_NOT_USE_OR_I_WILL_HUNT_YOU_DOWN = 0x00010000,
|
||||
// If this bit is set, the frame may have a transform that it applies
|
||||
// to its coordinate system (e.g. CSS transform, SVG foreignObject).
|
||||
// This is used primarily in GetTransformMatrix to optimize for the
|
||||
// common case.
|
||||
NS_FRAME_MAY_BE_TRANSFORMED = 0x00010000,
|
||||
|
||||
#ifdef IBMBIDI
|
||||
// If this bit is set, the frame itself is a bidi continuation,
|
||||
@ -901,6 +906,12 @@ public:
|
||||
*/
|
||||
virtual PRBool NeedsView() { return PR_FALSE; }
|
||||
|
||||
/**
|
||||
* Returns whether this frame has a transform matrix applied to it. This is true
|
||||
* if we have the -moz-transform property or if we're an SVGForeignObjectFrame.
|
||||
*/
|
||||
virtual PRBool IsTransformed() const;
|
||||
|
||||
/**
|
||||
* This frame needs a view with a widget (e.g. because it's fixed
|
||||
* positioned), so we call this to create the widget. If widgets for
|
||||
@ -1550,7 +1561,19 @@ public:
|
||||
* @see nsGkAtoms
|
||||
*/
|
||||
virtual nsIAtom* GetType() const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a transformation matrix that converts points in this frame's coordinate space
|
||||
* to points in some ancestor frame's coordinate space. The frame decides which ancestor
|
||||
* it will use as a reference point. If this frame has no ancestor, aOutAncestor will be
|
||||
* set to null.
|
||||
*
|
||||
* @param aOutAncestor [out] The ancestor frame the frame has chosen. If this frame has no
|
||||
* ancestor, aOutAncestor will be nsnull.
|
||||
* @return A gfxMatrix that converts points in this frame's coordinate space into
|
||||
* points in aOutAncestor's coordinate space.
|
||||
*/
|
||||
virtual gfxMatrix GetTransformMatrix(nsIFrame **aOutAncestor);
|
||||
|
||||
/**
|
||||
* Bit-flags to pass to IsFrameOfType()
|
||||
@ -1666,6 +1689,20 @@ public:
|
||||
nscoord aOffsetX, nscoord aOffsetY,
|
||||
nsIFrame* aForChild, PRBool aImmediate);
|
||||
|
||||
/**
|
||||
* Helper function that funnels an InvalidateInternal request up to the
|
||||
* parent. This function is used so that if MOZ_SVG is not defined, we still
|
||||
* have unified control paths in the InvalidateInternal chain.
|
||||
*
|
||||
* @param aDamageRect The rect to invalidate.
|
||||
* @param aX The x offset from the origin of this frame to the rectangle.
|
||||
* @param aY The y offset from the origin of this frame to the rectangle.
|
||||
* @param aImmediate Whether to redraw immediately.
|
||||
* @return None, though this funnels the request up to the parent frame.
|
||||
*/
|
||||
void InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
|
||||
nscoord aY, PRBool aImmediate);
|
||||
|
||||
/**
|
||||
* Take two rectangles in the coordinate system of this frame which
|
||||
* have the same origin and invalidate the difference between them.
|
||||
|
@ -111,6 +111,9 @@ include text-shadow/reftest.list
|
||||
# text-transform/
|
||||
include text-transform/reftest.list
|
||||
|
||||
# -moz-transform/
|
||||
include transform/reftest.list
|
||||
|
||||
# xul-document-load/
|
||||
include xul-document-load/reftest.list
|
||||
|
||||
|
12
layout/reftests/transform/abspos-1-ref.html
Normal file
12
layout/reftests/transform/abspos-1-ref.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 100px; height: 200px; position: relative; left: 50px; top: 50px; background-color: gold;">
|
||||
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
<div style="background-color: navy; color: gold; width: 200px; height: 100px; position: absolute; left: 50px; top: 100px;">
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
12
layout/reftests/transform/abspos-1a.html
Normal file
12
layout/reftests/transform/abspos-1a.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 100px; height: 200px; -moz-transform: translate(50px); background-color: gold;">
|
||||
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
<div style="background-color: navy; color: gold; width: 200px; height: 100px; position: absolute; left: 50px; top: 100px;">
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
12
layout/reftests/transform/abspos-1b.html
Normal file
12
layout/reftests/transform/abspos-1b.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 100px; height: 200px; -moz-transform: translate(50px) ;background-color: gold;">
|
||||
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
<div style="background-color: navy; color: gold; width: 200px; height: 100px; position: fixed; left: 50px; top: 100px;">
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
12
layout/reftests/transform/abspos-1c.html
Normal file
12
layout/reftests/transform/abspos-1c.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 100px; height: 200px; -moz-transform: translate(50px) ;background-color: gold;">
|
||||
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
<div style="background-color: navy; color: gold; width: 200px; height: 100px; position: fixed; right: -150px; bottom: 0px;">
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
12
layout/reftests/transform/abspos-1d.html
Normal file
12
layout/reftests/transform/abspos-1d.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 100px; height: 200px; -moz-transform: translate(50px) ;background-color: gold;">
|
||||
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
<div style="background-color: navy; color: gold; width: 200px; height: 100px; position: absolute; right: -150px; bottom: 0px;">
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
12
layout/reftests/transform/abspos-1e.html
Normal file
12
layout/reftests/transform/abspos-1e.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 100px; height: 200px; -moz-transform: translate(50px) ;background-color: gold;">
|
||||
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
<div style="background-color: navy; color: gold; width: 200px; height: 100px; position: absolute; right: -151px; bottom: 0px;">
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/origin-1-ref.html
Normal file
9
layout/reftests/transform/origin-1-ref.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:200px;height:100px;border:1px solid black; -moz-transform: rotate(45deg);">
|
||||
Some text!
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/origin-1a.html
Normal file
9
layout/reftests/transform/origin-1a.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:200px;height:100px;border:1px solid black; -moz-transform: rotate(45deg); -moz-transform-origin: 0% 0%">
|
||||
Some text!
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/origin-1b.html
Normal file
9
layout/reftests/transform/origin-1b.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:200px;height:100px;border:1px solid black; -moz-transform: rotate(45deg); -moz-transform-origin:100% 50%">
|
||||
Some text!
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/origin-2-ref.html
Normal file
9
layout/reftests/transform/origin-2-ref.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:200px;height:100px;border:1px solid black; -moz-transform: rotate(45deg);">
|
||||
Some text!
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/origin-2a.html
Normal file
9
layout/reftests/transform/origin-2a.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:200px;height:100px;border:1px solid black; -moz-transform: rotate(45deg); -moz-transform-origin: 101px 51px;">
|
||||
Some text!
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/origin-2b.html
Normal file
9
layout/reftests/transform/origin-2b.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:200px;height:100px;border:1px solid black; -moz-transform: rotate(45deg); -moz-transform-origin: 101px 50%;">
|
||||
Some text!
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/origin-2c.html
Normal file
9
layout/reftests/transform/origin-2c.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:200px;height:100px;border:1px solid black; -moz-transform: rotate(45deg); -moz-transform-origin: 50% 51px;">
|
||||
Some text!
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
8
layout/reftests/transform/origin-name-1-ref.html
Normal file
8
layout/reftests/transform/origin-name-1-ref.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-left: 300px; margin-top:300px; width:100px; height:200px; background-color:#202040; -moz-transform: rotate(45deg); -moz-transform-origin: 0% 0%;">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
8
layout/reftests/transform/origin-name-1a.html
Normal file
8
layout/reftests/transform/origin-name-1a.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-left: 300px; margin-top:300px; width:100px; height:200px; background-color:#202040; -moz-transform: rotate(45deg); -moz-transform-origin: top left;">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
8
layout/reftests/transform/origin-name-1b.html
Normal file
8
layout/reftests/transform/origin-name-1b.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-left: 300px; margin-top:300px; width:100px; height:200px; background-color:#202040; -moz-transform: rotate(45deg); -moz-transform-origin: left top;">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
8
layout/reftests/transform/origin-name-2-ref.html
Normal file
8
layout/reftests/transform/origin-name-2-ref.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-left: 300px; margin-top:300px; width:100px; height:200px; background-color:#202040; -moz-transform: rotate(45deg); -moz-transform-origin: 50% 0%;">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
8
layout/reftests/transform/origin-name-2a.html
Normal file
8
layout/reftests/transform/origin-name-2a.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-left: 300px; margin-top:300px; width:100px; height:200px; background-color:#202040; -moz-transform: rotate(45deg); -moz-transform-origin: top;">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
8
layout/reftests/transform/origin-name-2b.html
Normal file
8
layout/reftests/transform/origin-name-2b.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-left: 300px; margin-top:300px; width:100px; height:200px; background-color:#202040; -moz-transform: rotate(45deg); -moz-transform-origin: top center;">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
8
layout/reftests/transform/origin-name-2c.html
Normal file
8
layout/reftests/transform/origin-name-2c.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-left: 300px; margin-top:300px; width:100px; height:200px; background-color:#202040; -moz-transform: rotate(45deg); -moz-transform-origin: center top;">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
8
layout/reftests/transform/origin-name-3-ref.html
Normal file
8
layout/reftests/transform/origin-name-3-ref.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-left: 300px; margin-top:300px; width:100px; height:200px; background-color:#202040; -moz-transform: rotate(45deg); -moz-transform-origin: 100% 0%;">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
8
layout/reftests/transform/origin-name-3a.html
Normal file
8
layout/reftests/transform/origin-name-3a.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-left: 300px; margin-top:300px; width:100px; height:200px; background-color:#202040; -moz-transform: rotate(45deg); -moz-transform-origin: top right;">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
8
layout/reftests/transform/origin-name-3b.html
Normal file
8
layout/reftests/transform/origin-name-3b.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-left: 300px; margin-top:300px; width:100px; height:200px; background-color:#202040; -moz-transform: rotate(45deg); -moz-transform-origin: right top;">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
layout/reftests/transform/percent-1-ref.html
Normal file
14
layout/reftests/transform/percent-1-ref.html
Normal file
@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
.transformed
|
||||
{
|
||||
-moz-transform: rotate(10deg) translatex(50px) rotate(10deg) translatey(50px) skewx(10deg) translate(25px);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:100px; height:50px; background-color:gold; position: absolute; left:100px; top:100px;" class="transformed">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
layout/reftests/transform/percent-1a.html
Normal file
14
layout/reftests/transform/percent-1a.html
Normal file
@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
.transformed
|
||||
{
|
||||
-moz-transform: rotate(10deg) translatex(50%) rotate(10deg) translatey(50px) skewx(10deg) translate(25px);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:100px; height:50px; background-color:gold; position: absolute; left:100px; top:100px;" class="transformed">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
layout/reftests/transform/percent-1b.html
Normal file
14
layout/reftests/transform/percent-1b.html
Normal file
@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
.transformed
|
||||
{
|
||||
-moz-transform: rotate(10deg) translatex(50px) rotate(10deg) translatey(100%) skewx(10deg) translate(25px);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:100px; height:50px; background-color:gold; position: absolute; left:100px; top:100px;" class="transformed">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
layout/reftests/transform/percent-1c.html
Normal file
14
layout/reftests/transform/percent-1c.html
Normal file
@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
.transformed
|
||||
{
|
||||
-moz-transform: rotate(10deg) translatex(50px) rotate(10deg) translatey(50px) skewx(10deg) translate(25%, 50%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:100px; height:50px; background-color:gold; position: absolute; left:100px; top:100px;" class="transformed">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
layout/reftests/transform/percent-1d.html
Normal file
14
layout/reftests/transform/percent-1d.html
Normal file
@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
.transformed
|
||||
{
|
||||
-moz-transform: rotate(10deg) translatex(50%) rotate(10deg) translatey(100%) skewx(10deg) translate(25px);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:100px; height:50px; background-color:gold; position: absolute; left:100px; top:100px;" class="transformed">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
layout/reftests/transform/percent-1e.html
Normal file
14
layout/reftests/transform/percent-1e.html
Normal file
@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
.transformed
|
||||
{
|
||||
-moz-transform: rotate(10deg) translatex(50%) rotate(10deg) translatey(100%) skewx(10deg) translate(25%, 50%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:100px; height:50px; background-color:gold; position: absolute; left:100px; top:100px;" class="transformed">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
layout/reftests/transform/percent-1f.html
Normal file
14
layout/reftests/transform/percent-1f.html
Normal file
@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
.transformed
|
||||
{
|
||||
-moz-transform: rotate(10deg) translatex(50%) rotate(10deg) translatey(50px) skewx(10deg) translate(25%, 50%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:100px; height:50px; background-color:gold; position: absolute; left:100px; top:100px;" class="transformed">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
14
layout/reftests/transform/percent-1g.html
Normal file
14
layout/reftests/transform/percent-1g.html
Normal file
@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
.transformed
|
||||
{
|
||||
-moz-transform: rotate(10deg) translatex(50px) rotate(10deg) translatey(100%) skewx(10deg) translate(25%, 50%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:100px; height:50px; background-color:gold; position: absolute; left:100px; top:100px;" class="transformed">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
63
layout/reftests/transform/reftest.list
Normal file
63
layout/reftests/transform/reftest.list
Normal file
@ -0,0 +1,63 @@
|
||||
# translatex should act like position: relative
|
||||
== translatex-1a.html translatex-1-ref.html
|
||||
== translatex-1b.html translatex-1-ref.html
|
||||
== translatex-1c.html translatex-1-ref.html
|
||||
== translatex-1d.html translatex-1-ref.html
|
||||
== translatex-1e.html translatex-1-ref.html
|
||||
== translatex-1a.html translatex-1-ref-2.html
|
||||
# translatey should act like position: relative
|
||||
== translatey-1a.html translatey-1-ref.html
|
||||
== translatey-1b.html translatey-1-ref.html
|
||||
== translatey-1c.html translatey-1-ref.html
|
||||
== translatey-1d.html translatey-1-ref.html
|
||||
== translatey-1e.html translatey-1-ref.html
|
||||
# matrices defined to be translations should act like position: relative
|
||||
== translatex-2.html translatex-1-ref.html
|
||||
== translatey-2.html translatey-1-ref.html
|
||||
# translate should act like position: relative
|
||||
== translate-1a.html translate-1-ref.html
|
||||
== translate-1b.html translate-1-ref.html
|
||||
== translate-1c.html translate-1-ref.html
|
||||
== translate-1d.html translate-1-ref.html
|
||||
== translate-1e.html translate-1-ref.html
|
||||
# rotate: Several rotations of the same object should be idempotent
|
||||
== rotate-1a.html rotate-1-ref.html
|
||||
== rotate-1b.html rotate-1-ref.html
|
||||
== rotate-1c.html rotate-1-ref.html
|
||||
== rotate-1d.html rotate-1-ref.html
|
||||
== rotate-1e.html rotate-1-ref.html
|
||||
# rotate: 90deg rotations should be indistinguishable from objects constructed to look the same.
|
||||
== rotate-2a.html rotate-2-ref.html
|
||||
# -moz-transform-origin: We should NOT get the same images when using different -moz-transform-origins.
|
||||
!= origin-1a.html origin-1-ref.html
|
||||
!= origin-1b.html origin-1-ref.html
|
||||
# -moz-transform-origin: We should get the same images when using equivalent -moz-transform-origins.
|
||||
== origin-2a.html origin-2-ref.html
|
||||
== origin-2b.html origin-2-ref.html
|
||||
== origin-2c.html origin-2-ref.html
|
||||
# translate with percentages should be indistinguishable from translate with equivalent values.
|
||||
== percent-1a.html percent-1-ref.html
|
||||
== percent-1b.html percent-1-ref.html
|
||||
== percent-1c.html percent-1-ref.html
|
||||
== percent-1d.html percent-1-ref.html
|
||||
== percent-1e.html percent-1-ref.html
|
||||
== percent-1f.html percent-1-ref.html
|
||||
== percent-1g.html percent-1-ref.html
|
||||
# Transformed elements are abs-pos and fixed-pos containing blocks.
|
||||
== abspos-1a.html abspos-1-ref.html
|
||||
== abspos-1b.html abspos-1-ref.html
|
||||
== abspos-1c.html abspos-1-ref.html
|
||||
== abspos-1d.html abspos-1-ref.html
|
||||
!= abspos-1e.html abspos-1-ref.html
|
||||
# Origin can use "top" "right" etc.
|
||||
== origin-name-1a.html origin-name-1-ref.html
|
||||
== origin-name-1b.html origin-name-1-ref.html
|
||||
== origin-name-2a.html origin-name-2-ref.html
|
||||
== origin-name-2b.html origin-name-2-ref.html
|
||||
== origin-name-2c.html origin-name-2-ref.html
|
||||
== origin-name-3a.html origin-name-3-ref.html
|
||||
== origin-name-3b.html origin-name-3-ref.html
|
||||
# SVG effects should work on transforms.
|
||||
== transform-svg-1a.xhtml transform-svg-1-ref.xhtml
|
||||
== transform-svg-2a.xhtml transform-svg-2-ref.xhtml
|
||||
!= transform-svg-2a.xhtml transform-svg-2-fail.xhtml
|
9
layout/reftests/transform/rotate-1-ref.html
Normal file
9
layout/reftests/transform/rotate-1-ref.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: rotate(45deg);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/rotate-1a.html
Normal file
9
layout/reftests/transform/rotate-1a.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: rotate(45deg) rotate(360deg);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/rotate-1b.html
Normal file
9
layout/reftests/transform/rotate-1b.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: rotate(45deg) rotate(400grad);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/rotate-1c.html
Normal file
9
layout/reftests/transform/rotate-1c.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: rotate(45deg) rotate(100deg) rotate(80deg) rotate(200grad);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/rotate-1d.html
Normal file
9
layout/reftests/transform/rotate-1d.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: rotate(-45deg) rotate(100grad);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/rotate-1e.html
Normal file
9
layout/reftests/transform/rotate-1e.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: rotate(-135deg) rotate(3.1415926535897932384626433rad);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/rotate-2-ref.html
Normal file
9
layout/reftests/transform/rotate-2-ref.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:200px;height:100px;border:1px solid black;">
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/rotate-2a.html
Normal file
9
layout/reftests/transform/rotate-2a.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width:100px;height:200px;-moz-transform: rotate(-90deg) translate(50px, -50px); border: 1px solid black;">
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
12
layout/reftests/transform/transform-svg-1-ref.xhtml
Normal file
12
layout/reftests/transform/transform-svg-1-ref.xhtml
Normal file
@ -0,0 +1,12 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<body style="margin:0">
|
||||
<div style="position: relative; left:100px; top:100px; width:300px; height:300px; background:lime;">
|
||||
<div style="height:200px;"/>
|
||||
<div style="height:100px; background:blue;"/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
20
layout/reftests/transform/transform-svg-1a.xhtml
Normal file
20
layout/reftests/transform/transform-svg-1a.xhtml
Normal file
@ -0,0 +1,20 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<body style="margin:0">
|
||||
<div style="clip-path: url(#c1); width:400px; height:200px; background:lime; -moz-transform: translate(100px, 100px);">
|
||||
<div style="height:200px;"/>
|
||||
<div style="height:200px; background:blue;"/>
|
||||
</div>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:clipPath id="c1" clipPathUnits="userSpaceOnuse">
|
||||
<svg:rect x="0" y="0" width="300" height="300"/>
|
||||
</svg:clipPath>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
20
layout/reftests/transform/transform-svg-1b.xhtml
Normal file
20
layout/reftests/transform/transform-svg-1b.xhtml
Normal file
@ -0,0 +1,20 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<body style="margin:0">
|
||||
<div style="clip-path: url(#c1); width:400px; height:400px; background:blue; -moz-transform: rotate(135deg);">
|
||||
<div style="height:200px;"/>
|
||||
<div style="height:200px; background:lime;"/>
|
||||
</div>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:clipPath id="c1" clipPathUnits="userSpaceOnuse">
|
||||
<svg:rect x="0" y="0" width="300" height="300"/>
|
||||
</svg:clipPath>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
20
layout/reftests/transform/transform-svg-2-fail.xhtml
Normal file
20
layout/reftests/transform/transform-svg-2-fail.xhtml
Normal file
@ -0,0 +1,20 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<body style="margin:0">
|
||||
<div style="clip-path: url(#c1); width:400px; height:400px; background:blue;">
|
||||
<div style="height:200px;"/>
|
||||
<div style="height:200px; background:lime;"/>
|
||||
</div>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:clipPath id="c1" clipPathUnits="userSpaceOnuse">
|
||||
<svg:circle cx="100" cy="100" r="200"/>
|
||||
</svg:clipPath>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
20
layout/reftests/transform/transform-svg-2-ref.xhtml
Normal file
20
layout/reftests/transform/transform-svg-2-ref.xhtml
Normal file
@ -0,0 +1,20 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<body style="margin:0">
|
||||
<div style="clip-path: url(#c1); width:400px; height:400px; background:blue; position: relative; left:100px; top:100px;">
|
||||
<div style="height:200px;"/>
|
||||
<div style="height:200px; background:lime;"/>
|
||||
</div>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:clipPath id="c1" clipPathUnits="userSpaceOnuse">
|
||||
<svg:circle cx="200" cy="200" r="200"/>
|
||||
</svg:clipPath>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
20
layout/reftests/transform/transform-svg-2a.xhtml
Normal file
20
layout/reftests/transform/transform-svg-2a.xhtml
Normal file
@ -0,0 +1,20 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<body style="margin:0">
|
||||
<div style="clip-path: url(#c1); width:400px; height:400px; background:blue; -moz-transform: translate(100px);">
|
||||
<div style="height:200px;"/>
|
||||
<div style="height:200px; background:lime;"/>
|
||||
</div>
|
||||
|
||||
<svg:svg height="0">
|
||||
<svg:clipPath id="c1" clipPathUnits="userSpaceOnuse">
|
||||
<svg:circle cx="200" cy="200" r="200"/>
|
||||
</svg:clipPath>
|
||||
</svg:svg>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translate-1-ref.html
Normal file
9
layout/reftests/transform/translate-1-ref.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="position: relative; left: 50px; top: 50px;">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translate-1a.html
Normal file
9
layout/reftests/transform/translate-1a.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translate(50px);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translate-1b.html
Normal file
9
layout/reftests/transform/translate-1b.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translate(50px) rotate(360deg);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translate-1c.html
Normal file
9
layout/reftests/transform/translate-1c.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translate(25px) translate(25px);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translate-1d.html
Normal file
9
layout/reftests/transform/translate-1d.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translate(25px); position:relative; top:25px; left:25px;">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translate-1e.html
Normal file
9
layout/reftests/transform/translate-1e.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translate(50px) translate(-100px) translate(150px) translate(-50px);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatex-1-ref-2.html
Normal file
9
layout/reftests/transform/translatex-1-ref-2.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-left: 50px;">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatex-1-ref.html
Normal file
9
layout/reftests/transform/translatex-1-ref.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="position:relative; left:50px;">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatex-1a.html
Normal file
9
layout/reftests/transform/translatex-1a.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translatex(50px);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatex-1b.html
Normal file
9
layout/reftests/transform/translatex-1b.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translatex(50px) rotate(360deg);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatex-1c.html
Normal file
9
layout/reftests/transform/translatex-1c.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translatex(25px) translatex(25px);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatex-1d.html
Normal file
9
layout/reftests/transform/translatex-1d.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translatex(25px); position:relative; left:25px; top:0px;">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatex-1e.html
Normal file
9
layout/reftests/transform/translatex-1e.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translatex(50px) translatex(-100px) translatex(150px) translatex(-50px);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatex-2.html
Normal file
9
layout/reftests/transform/translatex-2.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: matrix(1, 0, 0, 1, 50px, 0);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatey-1-ref-2.html
Normal file
9
layout/reftests/transform/translatey-1-ref-2.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="margin-top: 50px;">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatey-1-ref.html
Normal file
9
layout/reftests/transform/translatey-1-ref.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="position:relative; top:50px;">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatey-1a.html
Normal file
9
layout/reftests/transform/translatey-1a.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translatey(50px);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatey-1b.html
Normal file
9
layout/reftests/transform/translatey-1b.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translatey(50px) rotate(360deg);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatey-1c.html
Normal file
9
layout/reftests/transform/translatey-1c.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translatey(25px) translatey(25px);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatey-1d.html
Normal file
9
layout/reftests/transform/translatey-1d.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translatey(25px); position:relative; top:25px; left:0px;">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatey-1e.html
Normal file
9
layout/reftests/transform/translatey-1e.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: translatey(50px) translatey(-100px) translatey(150px) translatey(-50px);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
9
layout/reftests/transform/translatey-2.html
Normal file
9
layout/reftests/transform/translatey-2.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div style="-moz-transform: matrix(1, 0, 0, 1, 0, 50px);">
|
||||
Test Text
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -122,6 +122,7 @@ EXPORTS = \
|
||||
nsStyleStructFwd.h \
|
||||
nsStyleStructInlines.h \
|
||||
nsStyleStructList.h \
|
||||
nsStyleTransformMatrix.h \
|
||||
nsStyleUtil.h \
|
||||
$(NULL)
|
||||
|
||||
@ -161,6 +162,7 @@ CPPSRCS = \
|
||||
nsStyleCoord.cpp \
|
||||
nsStyleSet.cpp \
|
||||
nsStyleStruct.cpp \
|
||||
nsStyleTransformMatrix.cpp \
|
||||
nsStyleUtil.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
@ -226,12 +226,14 @@ PRBool nsCSSDeclaration::AppendValueToString(nsCSSProperty aProperty, nsAString&
|
||||
const nsCSSValuePair *pair = static_cast<const nsCSSValuePair*>(storage);
|
||||
AppendCSSValueToString(aProperty, pair->mXValue, aResult);
|
||||
if (pair->mYValue != pair->mXValue ||
|
||||
(aProperty == eCSSProperty_background_position &&
|
||||
((aProperty == eCSSProperty_background_position ||
|
||||
aProperty == eCSSProperty__moz_transform_origin) &&
|
||||
pair->mXValue.GetUnit() != eCSSUnit_Inherit &&
|
||||
pair->mXValue.GetUnit() != eCSSUnit_Initial)) {
|
||||
// Only output a Y value if it's different from the X value
|
||||
// or if it's a background-position value other than 'initial'
|
||||
// or 'inherit'.
|
||||
// or 'inherit' or if it's a -moz-transform-origin value other
|
||||
// than 'initial' or 'inherit'.
|
||||
aResult.Append(PRUnichar(' '));
|
||||
AppendCSSValueToString(aProperty, pair->mYValue, aResult);
|
||||
}
|
||||
@ -329,6 +331,29 @@ nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty,
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Although Function is backed by an Array, we'll handle it separately
|
||||
* because it's a bit quirky.
|
||||
*/
|
||||
else if (eCSSUnit_Function == unit) {
|
||||
const nsCSSValue::Array* array = aValue.GetArrayValue();
|
||||
NS_ASSERTION(array->Count() >= 1, "Functions must have at least one element for the name.");
|
||||
|
||||
/* Append the function name. */
|
||||
AppendCSSValueToString(aProperty, array->Item(0), aResult);
|
||||
aResult.AppendLiteral("(");
|
||||
|
||||
/* Now, step through the function contents, writing each of them as we go. */
|
||||
for (PRUint16 index = 1; index < array->Count(); ++index) {
|
||||
AppendCSSValueToString(aProperty, array->Item(index), aResult);
|
||||
|
||||
/* If we're not at the final element, append a comma. */
|
||||
if (index + 1 != array->Count())
|
||||
aResult.AppendLiteral(", ");
|
||||
}
|
||||
|
||||
/* Finally, append the closing parenthesis. */
|
||||
aResult.AppendLiteral(")");
|
||||
}
|
||||
else if (eCSSUnit_Integer == unit) {
|
||||
nsAutoString tmpStr;
|
||||
tmpStr.AppendInt(aValue.GetIntValue(), 10);
|
||||
@ -453,6 +478,7 @@ nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty,
|
||||
case eCSSUnit_Attr:
|
||||
case eCSSUnit_Counter:
|
||||
case eCSSUnit_Counters: aResult.Append(PRUnichar(')')); break;
|
||||
case eCSSUnit_Function: break;
|
||||
case eCSSUnit_Integer: break;
|
||||
case eCSSUnit_Enumerated: break;
|
||||
case eCSSUnit_EnumColor: break;
|
||||
|
@ -336,6 +336,7 @@ CSS_KEY(lower-roman, lower_roman)
|
||||
CSS_KEY(lowercase, lowercase)
|
||||
CSS_KEY(ltr, ltr)
|
||||
CSS_KEY(margin-box, margin_box)
|
||||
CSS_KEY(matrix, matrix)
|
||||
CSS_KEY(medium, medium)
|
||||
CSS_KEY(menu, menu)
|
||||
CSS_KEY(menutext, menutext)
|
||||
@ -391,11 +392,15 @@ CSS_KEY(ridge, ridge)
|
||||
CSS_KEY(right, right)
|
||||
CSS_KEY(right-side, right_side)
|
||||
CSS_KEY(rightwards, rightwards)
|
||||
CSS_KEY(rotate, rotate)
|
||||
CSS_KEY(round, round)
|
||||
CSS_KEY(row-resize, row_resize)
|
||||
CSS_KEY(rtl, rtl)
|
||||
CSS_KEY(s, s)
|
||||
CSS_KEY(s-resize, s_resize)
|
||||
CSS_KEY(scale, scale)
|
||||
CSS_KEY(scalex, scalex)
|
||||
CSS_KEY(scaley, scaley)
|
||||
CSS_KEY(scroll, scroll)
|
||||
CSS_KEY(scrollbar, scrollbar)
|
||||
CSS_KEY(scrollbar-small, scrollbar_small)
|
||||
@ -410,6 +415,9 @@ CSS_KEY(semi-expanded, semi_expanded)
|
||||
CSS_KEY(separate, separate)
|
||||
CSS_KEY(show, show)
|
||||
CSS_KEY(silent, silent)
|
||||
CSS_KEY(skew, skew)
|
||||
CSS_KEY(skewx, skewx)
|
||||
CSS_KEY(skewy, skewy)
|
||||
CSS_KEY(slow, slow)
|
||||
CSS_KEY(slower, slower)
|
||||
CSS_KEY(small, small)
|
||||
@ -450,6 +458,9 @@ CSS_KEY(threedshadow, threedshadow)
|
||||
CSS_KEY(toggle, toggle)
|
||||
CSS_KEY(top, top)
|
||||
CSS_KEY(top-outside, top_outside)
|
||||
CSS_KEY(translate, translate)
|
||||
CSS_KEY(translatex, translatex)
|
||||
CSS_KEY(translatey, translatey)
|
||||
CSS_KEY(tri-state, tri_state)
|
||||
CSS_KEY(ultra-condensed, ultra_condensed)
|
||||
CSS_KEY(ultra-expanded, ultra_expanded)
|
||||
|
@ -83,6 +83,8 @@
|
||||
#include "math.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
// Flags for ParseVariant method
|
||||
#define VARIANT_KEYWORD 0x000001 // K
|
||||
@ -268,6 +270,7 @@ protected:
|
||||
|
||||
PRBool ExpectSymbol(PRUnichar aSymbol, PRBool aSkipWS);
|
||||
PRBool ExpectEndProperty();
|
||||
PRBool CheckEndProperty();
|
||||
nsSubstring* NextIdent();
|
||||
void SkipUntil(PRUnichar aStopSymbol);
|
||||
void SkipRuleSet();
|
||||
@ -388,6 +391,8 @@ protected:
|
||||
PRBool ParseBackground();
|
||||
PRBool ParseBackgroundPosition();
|
||||
PRBool ParseBackgroundPositionValues();
|
||||
PRBool ParseBoxPosition(nsCSSValuePair& aOut);
|
||||
PRBool ParseBoxPositionValues(nsCSSValuePair& aOut);
|
||||
PRBool ParseBorderColor();
|
||||
PRBool ParseBorderColors(nsCSSValueList** aResult,
|
||||
nsCSSProperty aProperty);
|
||||
@ -420,6 +425,7 @@ protected:
|
||||
PRBool ParseListStyle();
|
||||
PRBool ParseMargin();
|
||||
PRBool ParseMarks(nsCSSValue& aValue);
|
||||
PRBool ParseMozTransform();
|
||||
PRBool ParseOutline();
|
||||
PRBool ParseOverflow();
|
||||
PRBool ParsePadding();
|
||||
@ -477,6 +483,20 @@ protected:
|
||||
return mParsingCompoundProperty;
|
||||
}
|
||||
|
||||
/* Functions for -moz-transform Parsing */
|
||||
PRBool ReadSingleTransform(nsCSSValueList**& aTail);
|
||||
PRBool ParseFunction(const nsString &aFunction, const PRInt32 aAllowedTypes[],
|
||||
PRUint16 aMinElems, PRUint16 aMaxElems,
|
||||
nsCSSValue &aValue);
|
||||
PRBool ParseFunctionInternals(const PRInt32 aVariantMask[],
|
||||
PRUint16 aMinElems,
|
||||
PRUint16 aMaxElems,
|
||||
nsTArray<nsCSSValue>& aOutput);
|
||||
|
||||
/* Functions for -moz-transform-origin Parsing */
|
||||
PRBool ParseMozTransformOrigin();
|
||||
|
||||
|
||||
/* Find and return the correct namespace ID for the prefix aPrefix.
|
||||
If the prefix cannot be resolved to a namespace, this method will
|
||||
return false. Otherwise it will return true. When returning
|
||||
@ -1256,24 +1276,39 @@ CSSParserImpl::ExpectSymbol(PRUnichar aSymbol,
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Checks to see if we're at the end of a property. If an error occurs during
|
||||
// the check, does not signal a parse error.
|
||||
PRBool
|
||||
CSSParserImpl::ExpectEndProperty()
|
||||
CSSParserImpl::CheckEndProperty()
|
||||
{
|
||||
if (!GetToken(PR_TRUE)) {
|
||||
return PR_TRUE; // properties may end with eof
|
||||
}
|
||||
if ((eCSSToken_Symbol == mToken.mType) &&
|
||||
((';' == mToken.mSymbol) || ('!' == mToken.mSymbol) || ('}' == mToken.mSymbol))) {
|
||||
((';' == mToken.mSymbol) ||
|
||||
('!' == mToken.mSymbol) ||
|
||||
('}' == mToken.mSymbol))) {
|
||||
// XXX need to verify that ! is only followed by "important [;|}]
|
||||
// XXX this requires a multi-token pushback buffer
|
||||
UngetToken();
|
||||
return PR_TRUE;
|
||||
}
|
||||
REPORT_UNEXPECTED_TOKEN(PEExpectEndValue);
|
||||
UngetToken();
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Checks if we're at the end of a property, raising an error if we're not.
|
||||
PRBool
|
||||
CSSParserImpl::ExpectEndProperty()
|
||||
{
|
||||
if (CheckEndProperty())
|
||||
return PR_TRUE;
|
||||
|
||||
// If we're here, we read something incorrect, so we should report it.
|
||||
REPORT_UNEXPECTED_TOKEN(PRExpectEndValue);
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
nsSubstring*
|
||||
CSSParserImpl::NextIdent()
|
||||
@ -4178,7 +4213,7 @@ CSSParserImpl::ParsePositiveVariant(nsCSSValue& aValue,
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
else if(aValue.GetUnit() == eCSSUnit_Percent) {
|
||||
else if (aValue.GetUnit() == eCSSUnit_Percent) {
|
||||
if (aValue.GetPercentValue() < 0) {
|
||||
UngetToken();
|
||||
return PR_FALSE;
|
||||
@ -4786,6 +4821,8 @@ CSSParserImpl::ParseProperty(nsCSSProperty aPropID)
|
||||
return ParseBorderRadius();
|
||||
case eCSSProperty__moz_outline_radius:
|
||||
return ParseOutlineRadius();
|
||||
case eCSSProperty_box_shadow:
|
||||
return ParseBoxShadow();
|
||||
case eCSSProperty_clip:
|
||||
return ParseRect(mTempData.mDisplay.mClip, eCSSProperty_clip);
|
||||
case eCSSProperty__moz_column_rule:
|
||||
@ -4849,8 +4886,10 @@ CSSParserImpl::ParseProperty(nsCSSProperty aPropID)
|
||||
return ParseSize();
|
||||
case eCSSProperty_text_shadow:
|
||||
return ParseTextShadow();
|
||||
case eCSSProperty_box_shadow:
|
||||
return ParseBoxShadow();
|
||||
case eCSSProperty__moz_transform:
|
||||
return ParseMozTransform();
|
||||
case eCSSProperty__moz_transform_origin:
|
||||
return ParseMozTransformOrigin();
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
case eCSSProperty_fill:
|
||||
@ -4908,7 +4947,6 @@ CSSParserImpl::ParseProperty(nsCSSProperty aPropID)
|
||||
// The user can't use these
|
||||
REPORT_UNEXPECTED(PEInaccessibleProperty2);
|
||||
return PR_FALSE;
|
||||
|
||||
default: // must be single property
|
||||
{
|
||||
nsCSSValue value;
|
||||
@ -4999,6 +5037,8 @@ CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
|
||||
case eCSSProperty_quotes:
|
||||
case eCSSProperty_size:
|
||||
case eCSSProperty_text_shadow:
|
||||
case eCSSProperty__moz_transform:
|
||||
case eCSSProperty__moz_transform_origin:
|
||||
case eCSSProperty_COUNT:
|
||||
#ifdef MOZ_SVG
|
||||
case eCSSProperty_fill:
|
||||
@ -5565,7 +5605,7 @@ CSSParserImpl::ParseAzimuth(nsCSSValue& aValue)
|
||||
}
|
||||
|
||||
static nsCSSValue
|
||||
BackgroundPositionMaskToCSSValue(PRInt32 aMask, PRBool isX)
|
||||
BoxPositionMaskToCSSValue(PRInt32 aMask, PRBool isX)
|
||||
{
|
||||
PRInt32 val = NS_STYLE_BG_POSITION_CENTER;
|
||||
if (isX) {
|
||||
@ -5744,8 +5784,7 @@ CSSParserImpl::ParseBackground()
|
||||
PRBool
|
||||
CSSParserImpl::ParseBackgroundPosition()
|
||||
{
|
||||
if (!ParseBackgroundPositionValues() ||
|
||||
!ExpectEndProperty())
|
||||
if (!ParseBoxPosition(mTempData.mColor.mBackPosition))
|
||||
return PR_FALSE;
|
||||
mTempData.SetPropertyBit(eCSSProperty_background_position);
|
||||
return PR_TRUE;
|
||||
@ -5753,10 +5792,29 @@ CSSParserImpl::ParseBackgroundPosition()
|
||||
|
||||
PRBool
|
||||
CSSParserImpl::ParseBackgroundPositionValues()
|
||||
{
|
||||
return ParseBoxPositionValues(mTempData.mColor.mBackPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses two values that correspond to positions in a box. These can be
|
||||
* values corresponding to percentages of the box, raw offsets, or keywords
|
||||
* like "top," "left center," etc.
|
||||
*
|
||||
* @param aOut The nsCSSValuePair where to place the result.
|
||||
* @return Whether or not the operation succeeded.
|
||||
*/
|
||||
PRBool CSSParserImpl::ParseBoxPosition(nsCSSValuePair &aOut)
|
||||
{
|
||||
// Need to read the box positions and the end of the property.
|
||||
return ParseBoxPositionValues(aOut) && ExpectEndProperty();
|
||||
}
|
||||
|
||||
PRBool CSSParserImpl::ParseBoxPositionValues(nsCSSValuePair &aOut)
|
||||
{
|
||||
// First try a percentage or a length value
|
||||
nsCSSValue &xValue = mTempData.mColor.mBackPosition.mXValue,
|
||||
&yValue = mTempData.mColor.mBackPosition.mYValue;
|
||||
nsCSSValue &xValue = aOut.mXValue,
|
||||
&yValue = aOut.mYValue;
|
||||
if (ParseVariant(xValue, VARIANT_HLP, nsnull)) {
|
||||
if (eCSSUnit_Inherit == xValue.GetUnit() ||
|
||||
eCSSUnit_Initial == xValue.GetUnit()) { // both are inherited or both are set to initial
|
||||
@ -5776,7 +5834,7 @@ CSSParserImpl::ParseBackgroundPositionValues()
|
||||
// The second keyword can only be 'center', 'top', or 'bottom'
|
||||
return PR_FALSE;
|
||||
}
|
||||
yValue = BackgroundPositionMaskToCSSValue(yVal, PR_FALSE);
|
||||
yValue = BoxPositionMaskToCSSValue(yVal, PR_FALSE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -5812,7 +5870,7 @@ CSSParserImpl::ParseBackgroundPositionValues()
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
xValue = BackgroundPositionMaskToCSSValue(mask, PR_TRUE);
|
||||
xValue = BoxPositionMaskToCSSValue(mask, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
@ -5826,8 +5884,8 @@ CSSParserImpl::ParseBackgroundPositionValues()
|
||||
}
|
||||
|
||||
// Create style values
|
||||
xValue = BackgroundPositionMaskToCSSValue(mask, PR_TRUE);
|
||||
yValue = BackgroundPositionMaskToCSSValue(mask, PR_FALSE);
|
||||
xValue = BoxPositionMaskToCSSValue(mask, PR_TRUE);
|
||||
yValue = BoxPositionMaskToCSSValue(mask, PR_FALSE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -6323,7 +6381,7 @@ CSSParserImpl::ParseCounterData(nsCSSValuePairList** aResult,
|
||||
*sv_end = singleValues + NS_ARRAY_LENGTH(singleValues);
|
||||
sv != sv_end; ++sv) {
|
||||
if (ident->LowerCaseEqualsASCII(sv->str)) {
|
||||
if (ExpectEndProperty()) {
|
||||
if (CheckEndProperty()) {
|
||||
nsCSSValuePairList* dataHead = new nsCSSValuePairList();
|
||||
if (!dataHead) {
|
||||
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
|
||||
@ -6614,6 +6672,373 @@ CSSParserImpl::ParseOneFamily(nsAString& aFamily)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// -moz-transform Parsing Implementation
|
||||
|
||||
/* Reads a function list of arguments. Do not call this function
|
||||
* directly; it's mean to be caled from ParseFunction.
|
||||
*/
|
||||
PRBool
|
||||
CSSParserImpl::ParseFunctionInternals(const PRInt32 aVariantMask[],
|
||||
PRUint16 aMinElems,
|
||||
PRUint16 aMaxElems,
|
||||
nsTArray<nsCSSValue> &aOutput)
|
||||
{
|
||||
for (PRUint16 index = 0; index < aMaxElems; ++index) {
|
||||
nsCSSValue newValue;
|
||||
if (!ParseVariant(newValue, aVariantMask[index], nsnull))
|
||||
return PR_FALSE;
|
||||
|
||||
if (!aOutput.AppendElement(newValue)) {
|
||||
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// See whether to continue or whether to look for end of function.
|
||||
if (!ExpectSymbol(',', PR_TRUE)) {
|
||||
// We need to read the closing parenthesis, and also must take care
|
||||
// that we haven't read too few symbols.
|
||||
return ExpectSymbol(')', PR_TRUE) && (index + 1) >= aMinElems;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're here, we finished looping without hitting the end, so we read too
|
||||
// many elements.
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/* Parses a function [ input of the form (a [, b]*) ] and stores it
|
||||
* as an nsCSSValue that holds a function of the form
|
||||
* function-name arg1 arg2 ... argN
|
||||
*
|
||||
* On error, the return value is PR_FALSE.
|
||||
*
|
||||
* @param aFunction The name of the function that we're reading.
|
||||
* @param aAllowedTypes An array of values corresponding to the legal
|
||||
* types for each element in the function. The zeroth element in the
|
||||
* array corresponds to the first function parameter, etc. The length
|
||||
* of this array _must_ be greater than or equal to aMaxElems or the
|
||||
* behavior is undefined.
|
||||
* @param aMinElems Minimum number of elements to read. Reading fewer than
|
||||
* this many elements will result in the function failing.
|
||||
* @param aMaxElems Maximum number of elements to read. Reading more than
|
||||
* this many elements will result in the function failing.
|
||||
* @param aValue (out) The value that was parsed.
|
||||
*/
|
||||
PRBool
|
||||
CSSParserImpl::ParseFunction(const nsString &aFunction,
|
||||
const PRInt32 aAllowedTypes[],
|
||||
PRUint16 aMinElems, PRUint16 aMaxElems,
|
||||
nsCSSValue &aValue)
|
||||
{
|
||||
typedef nsTArray<nsCSSValue>::size_type arrlen_t;
|
||||
|
||||
/* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1
|
||||
* elements stored in the the nsCSSValue::Array.
|
||||
*/
|
||||
static const arrlen_t MAX_ALLOWED_ELEMS = 0xFFFE;
|
||||
|
||||
/* Make a copy of the function name, since the reference is _probably_ to
|
||||
* mToken.mIdent, which is going to get overwritten during the course of this
|
||||
* function.
|
||||
*/
|
||||
nsString functionName(aFunction);
|
||||
|
||||
/* First things first... read the parenthesis. If it fails, abort. */
|
||||
if (!ExpectSymbol('(', PR_TRUE))
|
||||
return PR_FALSE;
|
||||
|
||||
/* Read in a list of values as an nsTArray, failing if we can't or if
|
||||
* it's out of bounds.
|
||||
*/
|
||||
nsTArray<nsCSSValue> foundValues;
|
||||
if (!ParseFunctionInternals(aAllowedTypes, aMinElems, aMaxElems,
|
||||
foundValues))
|
||||
return PR_FALSE;
|
||||
|
||||
/* Now, convert this nsTArray into an nsCSSValue::Array object.
|
||||
* We'll need N + 1 spots, one for the function name and the rest for the
|
||||
* arguments. In case the user has given us more than 2^16 - 2 arguments,
|
||||
* we'll truncate them at 2^16 - 2 arguments.
|
||||
*/
|
||||
PRUint16 numElements = (foundValues.Length() <= MAX_ALLOWED_ELEMS ?
|
||||
foundValues.Length() + 1 : MAX_ALLOWED_ELEMS);
|
||||
nsRefPtr<nsCSSValue::Array> convertedArray =
|
||||
nsCSSValue::Array::Create(numElements);
|
||||
if (!convertedArray) {
|
||||
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/* Copy things over. */
|
||||
convertedArray->Item(0).SetStringValue(functionName, eCSSUnit_String);
|
||||
for (PRUint16 index = 0; index + 1 < numElements; ++index)
|
||||
convertedArray->Item(index + 1) = foundValues[static_cast<arrlen_t>(index)];
|
||||
|
||||
/* Fill in the outparam value with the array. */
|
||||
aValue.SetArrayValue(convertedArray, eCSSUnit_Function);
|
||||
|
||||
/* Return it! */
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a token, determines the minimum and maximum number of function
|
||||
* parameters to read, along with the mask that should be used to read
|
||||
* those function parameters. If the token isn't a transform function,
|
||||
* returns an error.
|
||||
*
|
||||
* @param aToken The token identifying the function.
|
||||
* @param aMinElems [out] The minimum number of elements to read.
|
||||
* @param aMaxElems [out] The maximum number of elements to read
|
||||
* @param aVariantMask [out] The variant mask to use during parsing
|
||||
* @return Whether the information was loaded successfully.
|
||||
*/
|
||||
static PRBool GetFunctionParseInformation(nsCSSKeyword aToken,
|
||||
PRUint16 &aMinElems,
|
||||
PRUint16 &aMaxElems,
|
||||
const PRInt32 *& aVariantMask)
|
||||
{
|
||||
/* These types represent the common variant masks that will be used to
|
||||
* parse out the individual functions. The order in the enumeration
|
||||
* must match the order in which the masks are declared.
|
||||
*/
|
||||
enum { eLengthPercent,
|
||||
eTwoLengthPercents,
|
||||
eAngle,
|
||||
eNumber,
|
||||
eTwoNumbers,
|
||||
eMatrix,
|
||||
eNumVariantMasks };
|
||||
static const PRInt32 kMaxElemsPerFunction = 6;
|
||||
static const PRInt32 kVariantMasks[eNumVariantMasks][kMaxElemsPerFunction] = {
|
||||
{VARIANT_LENGTH | VARIANT_PERCENT},
|
||||
{VARIANT_LENGTH | VARIANT_PERCENT, VARIANT_LENGTH | VARIANT_PERCENT},
|
||||
{VARIANT_ANGLE},
|
||||
{VARIANT_NUMBER},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_LENGTH | VARIANT_PERCENT, VARIANT_LENGTH | VARIANT_PERCENT}};
|
||||
|
||||
#ifdef DEBUG
|
||||
static const PRUint8 kVariantMaskLengths[eNumVariantMasks] =
|
||||
{1, 2, 1, 1, 2, 6};
|
||||
#endif
|
||||
|
||||
PRInt32 variantIndex = eNumVariantMasks;
|
||||
|
||||
switch (aToken) {
|
||||
case eCSSKeyword_translatex:
|
||||
/* Exactly one length or percent. */
|
||||
variantIndex = eLengthPercent;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_translatey:
|
||||
/* Exactly one length or percent. */
|
||||
variantIndex = eLengthPercent;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_scalex:
|
||||
/* Exactly one scale factor. */
|
||||
variantIndex = eNumber;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_scaley:
|
||||
/* Exactly one scale factor. */
|
||||
variantIndex = eNumber;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_rotate:
|
||||
/* Exactly one angle. */
|
||||
variantIndex = eAngle;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_translate:
|
||||
/* One or two lengths or percents. */
|
||||
variantIndex = eTwoLengthPercents;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 2U;
|
||||
break;
|
||||
case eCSSKeyword_skew:
|
||||
/* Exactly one angle. */
|
||||
variantIndex = eAngle;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_scale:
|
||||
/* One or two scale factors. */
|
||||
variantIndex = eTwoNumbers;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 2U;
|
||||
break;
|
||||
case eCSSKeyword_skewx:
|
||||
/* Exactly one angle. */
|
||||
variantIndex = eAngle;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_skewy:
|
||||
/* Exactly one angle. */
|
||||
variantIndex = eAngle;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_matrix:
|
||||
/* Six values, which can be numbers, lengths, or percents. */
|
||||
variantIndex = eMatrix;
|
||||
aMinElems = 6U;
|
||||
aMaxElems = 6U;
|
||||
break;
|
||||
default:
|
||||
/* Oh dear, we didn't match. Report an error. */
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_ASSERTION(aMinElems > 0, "Didn't update minimum elements!");
|
||||
NS_ASSERTION(aMaxElems > 0, "Didn't update maximum elements!");
|
||||
NS_ASSERTION(aMinElems <= aMaxElems, "aMinElems > aMaxElems!");
|
||||
NS_ASSERTION(variantIndex >= 0, "Invalid variant mask!");
|
||||
NS_ASSERTION(variantIndex < eNumVariantMasks, "Invalid variant mask!");
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(aMaxElems <= kVariantMaskLengths[variantIndex],
|
||||
"Invalid aMaxElems for this variant mask.");
|
||||
#endif
|
||||
|
||||
// Convert the index into a mask.
|
||||
aVariantMask = kVariantMasks[variantIndex];
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Reads a single transform function from the tokenizer stream, reporting an
|
||||
* error if something goes wrong.
|
||||
*/
|
||||
PRBool CSSParserImpl::ReadSingleTransform(nsCSSValueList **& aTail)
|
||||
{
|
||||
typedef nsTArray<nsCSSValue>::size_type arrlen_t;
|
||||
|
||||
if (!GetToken(PR_TRUE))
|
||||
return PR_FALSE;
|
||||
|
||||
/* Check to make sure that we've read a function. */
|
||||
if (mToken.mType != eCSSToken_Function) {
|
||||
UngetToken();
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/* Load up the variant mask information for ParseFunction. If we can't,
|
||||
* abort.
|
||||
*/
|
||||
const PRInt32* variantMask;
|
||||
PRUint16 minElems, maxElems;
|
||||
if (!GetFunctionParseInformation(nsCSSKeywords::LookupKeyword(mToken.mIdent),
|
||||
minElems, maxElems, variantMask))
|
||||
return PR_FALSE;
|
||||
|
||||
/* Create a cell to populate, fail if we're out of memory. */
|
||||
nsAutoPtr<nsCSSValue> newCell(new nsCSSValue);
|
||||
if (!newCell) {
|
||||
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/* Try reading things in, failing if we can't */
|
||||
if (!ParseFunction(mToken.mIdent, variantMask, minElems, maxElems, *newCell))
|
||||
return PR_FALSE;
|
||||
|
||||
/* Wrap up our result in an nsCSSValueList cell. */
|
||||
nsAutoPtr<nsCSSValueList> toAppend(new nsCSSValueList);
|
||||
if (!toAppend)
|
||||
return PR_FALSE;
|
||||
|
||||
toAppend->mValue = *newCell;
|
||||
|
||||
/* Chain the element to the end of the transform list, then update the
|
||||
* list.
|
||||
*/
|
||||
*aTail = toAppend.forget();
|
||||
aTail = &(*aTail)->mNext;
|
||||
|
||||
/* It worked! Return true. */
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
/* Parses a -moz-transform property list by continuously reading in properties
|
||||
* and constructing a matrix from it.
|
||||
*/
|
||||
PRBool CSSParserImpl::ParseMozTransform()
|
||||
{
|
||||
mTempData.mDisplay.mTransform = nsnull;
|
||||
|
||||
/* First, check to see if this is some sort of keyword - none, inherit,
|
||||
* or initial.
|
||||
*/
|
||||
nsCSSValue keywordValue;
|
||||
if (ParseVariant(keywordValue, VARIANT_INHERIT | VARIANT_NONE, nsnull)) {
|
||||
/* Looks like it is. Make a new value list and fill it in, failing if
|
||||
* we can't.
|
||||
*/
|
||||
mTempData.mDisplay.mTransform = new nsCSSValueList;
|
||||
if (!mTempData.mDisplay.mTransform) {
|
||||
mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY);
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/* Inform the parser that everything worked. */
|
||||
mTempData.mDisplay.mTransform->mValue = keywordValue;
|
||||
mTempData.SetPropertyBit(eCSSProperty__moz_transform);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
/* We will read a nonempty list of transforms. Thus we'll read in a
|
||||
* transform, then continuously read transforms until we're no longer
|
||||
* able to do so.
|
||||
*/
|
||||
nsCSSValueList *transformList = nsnull;
|
||||
nsCSSValueList **tail = &transformList;
|
||||
do {
|
||||
/* Try reading a transform. If we fail to do so, abort. */
|
||||
if (!ReadSingleTransform(tail)) {
|
||||
delete transformList;
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
while (!CheckEndProperty());
|
||||
|
||||
/* Confirm that this is the end of the property and set error code
|
||||
* appropriately otherwise.
|
||||
*/
|
||||
if (!ExpectEndProperty()) {
|
||||
delete transformList;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/* Validate our data. */
|
||||
NS_ASSERTION(transformList, "Didn't read any transforms!");
|
||||
|
||||
mTempData.SetPropertyBit(eCSSProperty__moz_transform);
|
||||
mTempData.mDisplay.mTransform = transformList;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool CSSParserImpl::ParseMozTransformOrigin()
|
||||
{
|
||||
/* Read in a box position, fail if we can't. */
|
||||
if (!ParseBoxPosition(mTempData.mDisplay.mTransformOrigin))
|
||||
return PR_FALSE;
|
||||
|
||||
/* Set the property bit and return. */
|
||||
mTempData.SetPropertyBit(eCSSProperty__moz_transform_origin);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
CSSParserImpl::ParseFamily(nsCSSValue& aValue)
|
||||
{
|
||||
@ -6823,7 +7248,7 @@ CSSParserImpl::ParseMarks(nsCSSValue& aValue)
|
||||
{
|
||||
if (ParseVariant(aValue, VARIANT_HOK, nsCSSProps::kPageMarksKTable)) {
|
||||
if (eCSSUnit_Enumerated == aValue.GetUnit()) {
|
||||
if (PR_FALSE == ExpectEndProperty()) {
|
||||
if (PR_FALSE == CheckEndProperty()) {
|
||||
nsCSSValue second;
|
||||
if (ParseEnum(second, nsCSSProps::kPageMarksKTable)) {
|
||||
aValue.SetIntValue(aValue.GetIntValue() | second.GetIntValue(), eCSSUnit_Enumerated);
|
||||
@ -6967,7 +7392,7 @@ CSSParserImpl::ParseQuotes()
|
||||
// get mandatory close
|
||||
if (ParseVariant(quotes->mYValue, VARIANT_STRING,
|
||||
nsnull)) {
|
||||
if (ExpectEndProperty()) {
|
||||
if (CheckEndProperty()) {
|
||||
mTempData.SetPropertyBit(eCSSProperty_quotes);
|
||||
mTempData.mContent.mQuotes = quotesHead;
|
||||
return PR_TRUE;
|
||||
@ -7263,7 +7688,7 @@ CSSParserImpl::ParseDasharray()
|
||||
list->mValue = value;
|
||||
|
||||
for (;;) {
|
||||
if (ExpectEndProperty()) {
|
||||
if (CheckEndProperty()) {
|
||||
mTempData.SetPropertyBit(eCSSProperty_stroke_dasharray);
|
||||
mTempData.mSVG.mStrokeDasharray = listHead;
|
||||
return PR_TRUE;
|
||||
|
@ -500,6 +500,8 @@ CSS_PROP_TEXTRESET(text-decoration, text_decoration, TextDecoration, Text, mDeco
|
||||
CSS_PROP_TEXT(text-indent, text_indent, TextIndent, Text, mTextIndent, eCSSType_Value, nsnull)
|
||||
CSS_PROP_TEXT(text-shadow, text_shadow, TextShadow, Text, mTextShadow, eCSSType_ValueList, nsnull)
|
||||
CSS_PROP_TEXT(text-transform, text_transform, TextTransform, Text, mTextTransform, eCSSType_Value, kTextTransformKTable)
|
||||
CSS_PROP_DISPLAY(-moz-transform, _moz_transform, MozTransform, Display, mTransform, eCSSType_ValueList, kDisplayKTable)
|
||||
CSS_PROP_DISPLAY(-moz-transform-origin, _moz_transform_origin, MozTransformOrigin, Display, mTransformOrigin, eCSSType_ValuePair, kBackgroundPositionKTable)
|
||||
CSS_PROP_POSITION(top, top, Top, Position, mOffset.mTop, eCSSType_Value, nsnull)
|
||||
CSS_PROP_TEXTRESET(unicode-bidi, unicode_bidi, UnicodeBidi, Text, mUnicodeBidi, eCSSType_Value, kUnicodeBidiKTable)
|
||||
CSS_PROP_USERINTERFACE(-moz-user-focus, user_focus, MozUserFocus, UserInterface, mUserFocus, eCSSType_Value, kUserFocusKTable) // XXX bug 3935
|
||||
|
@ -213,7 +213,8 @@ nsCSSValueListRect::sides[4] = {
|
||||
|
||||
// --- nsCSSDisplay -----------------
|
||||
|
||||
nsCSSDisplay::nsCSSDisplay(void)
|
||||
/* During allocation, null-out the transform list. */
|
||||
nsCSSDisplay::nsCSSDisplay(void) : mTransform(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsCSSDisplay);
|
||||
}
|
||||
|
@ -279,6 +279,8 @@ struct nsCSSDisplay : public nsCSSStruct {
|
||||
nsCSSValue mOverflowY;
|
||||
nsCSSValue mVisibility;
|
||||
nsCSSValue mOpacity;
|
||||
nsCSSValueList *mTransform; // List of Arrays containing transform information
|
||||
nsCSSValuePair mTransformOrigin;
|
||||
|
||||
// temp fix for bug 24000
|
||||
nsCSSValue mBreakBefore;
|
||||
|
@ -104,7 +104,7 @@ nsCSSValue::nsCSSValue(nscolor aValue)
|
||||
nsCSSValue::nsCSSValue(nsCSSValue::Array* aValue, nsCSSUnit aUnit)
|
||||
: mUnit(aUnit)
|
||||
{
|
||||
NS_ASSERTION(eCSSUnit_Array <= aUnit && aUnit <= eCSSUnit_Counters,
|
||||
NS_ASSERTION(eCSSUnit_Array <= aUnit && aUnit <= eCSSUnit_Function,
|
||||
"bad unit");
|
||||
mValue.mArray = aValue;
|
||||
mValue.mArray->AddRef();
|
||||
@ -143,7 +143,7 @@ nsCSSValue::nsCSSValue(const nsCSSValue& aCopy)
|
||||
else if (eCSSUnit_Color == mUnit) {
|
||||
mValue.mColor = aCopy.mValue.mColor;
|
||||
}
|
||||
else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Counters) {
|
||||
else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Function) {
|
||||
mValue.mArray = aCopy.mValue.mArray;
|
||||
mValue.mArray->AddRef();
|
||||
}
|
||||
@ -185,7 +185,7 @@ PRBool nsCSSValue::operator==(const nsCSSValue& aOther) const
|
||||
else if (eCSSUnit_Color == mUnit) {
|
||||
return mValue.mColor == aOther.mValue.mColor;
|
||||
}
|
||||
else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Counters) {
|
||||
else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Function) {
|
||||
return *mValue.mArray == *aOther.mValue.mArray;
|
||||
}
|
||||
else if (eCSSUnit_URL == mUnit) {
|
||||
@ -249,7 +249,7 @@ void nsCSSValue::DoReset()
|
||||
{
|
||||
if (UnitHasStringValue()) {
|
||||
mValue.mString->Release();
|
||||
} else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Counters) {
|
||||
} else if (eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Function) {
|
||||
mValue.mArray->Release();
|
||||
} else if (eCSSUnit_URL == mUnit) {
|
||||
mValue.mURL->Release();
|
||||
@ -314,7 +314,7 @@ void nsCSSValue::SetColorValue(nscolor aValue)
|
||||
|
||||
void nsCSSValue::SetArrayValue(nsCSSValue::Array* aValue, nsCSSUnit aUnit)
|
||||
{
|
||||
NS_ASSERTION(eCSSUnit_Array <= aUnit && aUnit <= eCSSUnit_Counters,
|
||||
NS_ASSERTION(eCSSUnit_Array <= aUnit && aUnit <= eCSSUnit_Function,
|
||||
"bad unit");
|
||||
Reset();
|
||||
mUnit = aUnit;
|
||||
|
@ -71,6 +71,9 @@ enum nsCSSUnit {
|
||||
eCSSUnit_Array = 20, // (nsCSSValue::Array*) a list of values
|
||||
eCSSUnit_Counter = 21, // (nsCSSValue::Array*) a counter(string,[string]) value
|
||||
eCSSUnit_Counters = 22, // (nsCSSValue::Array*) a counters(string,string[,string]) value
|
||||
eCSSUnit_Function = 23, // (nsCSSValue::Array*) a function with parameters. First elem of array is name,
|
||||
// the rest of the values are arguments.
|
||||
|
||||
eCSSUnit_URL = 30, // (nsCSSValue::URL*) value
|
||||
eCSSUnit_Image = 31, // (nsCSSValue::Image*) value
|
||||
eCSSUnit_Integer = 50, // (int) simple value
|
||||
@ -221,7 +224,7 @@ public:
|
||||
|
||||
Array* GetArrayValue() const
|
||||
{
|
||||
NS_ASSERTION(eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Counters,
|
||||
NS_ASSERTION(eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Function,
|
||||
"not an array value");
|
||||
return mValue.mArray;
|
||||
}
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "nsDOMString.h"
|
||||
#include "nsIDOMCSS2Properties.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMCSSPrimitiveValue.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
#include "nsContentUtils.h"
|
||||
@ -72,6 +73,9 @@
|
||||
#include "nsInspectorCSSUtils.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsFrameManager.h"
|
||||
#include "nsCSSKeywords.h"
|
||||
#include "nsStyleCoord.h"
|
||||
#include "nsDisplayList.h"
|
||||
|
||||
#if defined(DEBUG_bzbarsky) || defined(DEBUG_caillon)
|
||||
#define DEBUG_ComputedDOMStyle
|
||||
@ -812,6 +816,125 @@ nsComputedDOMStyle::GetCounterIncrement(nsIDOMCSSValue** aValue)
|
||||
return CallQueryInterface(valueList, aValue);
|
||||
}
|
||||
|
||||
/* Convert the stored representation into a list of two values and then hand
|
||||
* it back.
|
||||
*/
|
||||
nsresult nsComputedDOMStyle::GetMozTransformOrigin(nsIDOMCSSValue **aValue)
|
||||
{
|
||||
/* We need to build up a list of two values. We'll call them
|
||||
* width and height.
|
||||
*/
|
||||
nsAutoPtr<nsROCSSPrimitiveValue> width(GetROCSSPrimitiveValue());
|
||||
nsAutoPtr<nsROCSSPrimitiveValue> height(GetROCSSPrimitiveValue());
|
||||
if (!width || !height)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
/* Now, get the values. */
|
||||
const nsStyleDisplay* display = GetStyleDisplay();
|
||||
SetValueToCoord(width, display->mTransformOrigin[0],
|
||||
&nsComputedDOMStyle::GetFrameBoundsWidthForTransform);
|
||||
SetValueToCoord(height, display->mTransformOrigin[1],
|
||||
&nsComputedDOMStyle::GetFrameBoundsHeightForTransform);
|
||||
|
||||
/* Store things as a value list, fail if we can't get one. */
|
||||
nsAutoPtr<nsDOMCSSValueList> valueList(GetROCSSValueList(PR_FALSE));
|
||||
if (!valueList)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
/* Chain on width and height, fail if we can't. */
|
||||
if (!valueList->AppendCSSValue(width))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
width.forget();
|
||||
if (!valueList->AppendCSSValue(height))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
height.forget();
|
||||
|
||||
/* Release the pointer and call query interface! We're done. */
|
||||
return CallQueryInterface(valueList.forget(), aValue);
|
||||
}
|
||||
|
||||
/* If the property is "none", hand back "none" wrapped in a value.
|
||||
* Otherwise, compute the aggregate transform matrix and hands it back in a
|
||||
* "matrix" wrapper.
|
||||
*/
|
||||
nsresult nsComputedDOMStyle::GetMozTransform(nsIDOMCSSValue **aValue)
|
||||
{
|
||||
static const PRInt32 NUM_FLOATS = 4;
|
||||
|
||||
/* First, get the display data. We'll need it. */
|
||||
const nsStyleDisplay* display = GetStyleDisplay();
|
||||
|
||||
/* If the "no transforms" flag is set, then we should construct a
|
||||
* single-element entry and hand it back.
|
||||
*/
|
||||
if (!display->mTransformPresent) {
|
||||
nsROCSSPrimitiveValue *val(GetROCSSPrimitiveValue());
|
||||
if (!val)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
/* Set it to "none." */
|
||||
val->SetIdent(eCSSKeyword_none);
|
||||
return CallQueryInterface(val, aValue);
|
||||
}
|
||||
|
||||
/* Otherwise, we need to compute the current value of the transform matrix,
|
||||
* store it in a string, and hand it back to the caller.
|
||||
*/
|
||||
nsAutoString resultString(NS_LITERAL_STRING("matrix("));
|
||||
|
||||
/* Now, we need to convert the matrix into a string. We'll start by taking
|
||||
* the first four entries and converting them directly to floating-point
|
||||
* values.
|
||||
*/
|
||||
for (PRInt32 index = 0; index < NUM_FLOATS; ++index) {
|
||||
resultString.AppendFloat(display->mTransform.GetMainMatrixEntry(index));
|
||||
resultString.Append(NS_LITERAL_STRING(", "));
|
||||
}
|
||||
|
||||
/* For the next part, we need to compute the translate values. This means
|
||||
* that we'll need to get the width and height of this object.
|
||||
*/
|
||||
PRInt32 cssPxWidth = 0, cssPxHeight = 0;
|
||||
|
||||
/* Use the inner frame for width and height. If we fail, assume zero.
|
||||
* TODO: There is no good way for us to represent the case where there's no
|
||||
* frame, which is problematic. The reason is that when we have percentage
|
||||
* transforms, there are a total of four stored matrix entries that influence
|
||||
* the transform based on the size of the element. However, this poses a
|
||||
* problem, because only two of these values can be explicitly referenced
|
||||
* using the named transforms. Until a real solution is found, we'll just
|
||||
* use this approach.
|
||||
*/
|
||||
nsRect bounds =
|
||||
(mInnerFrame ? nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame) :
|
||||
nsRect(0, 0, 0, 0));
|
||||
|
||||
/* Now, compute the dX and dY components by adding the stored coord value
|
||||
* (in CSS pixels) to the translate values.
|
||||
*/
|
||||
|
||||
float deltaX = nsPresContext::AppUnitsToFloatCSSPixels
|
||||
(display->mTransform.GetXTranslation(bounds));
|
||||
float deltaY = nsPresContext::AppUnitsToFloatCSSPixels
|
||||
(display->mTransform.GetYTranslation(bounds));
|
||||
|
||||
|
||||
/* Append these values! */
|
||||
resultString.AppendFloat(deltaX);
|
||||
resultString.Append(NS_LITERAL_STRING("px, "));
|
||||
resultString.AppendFloat(deltaY);
|
||||
resultString.Append(NS_LITERAL_STRING("px)"));
|
||||
|
||||
/* Create a value to hold our result. */
|
||||
nsROCSSPrimitiveValue* rv(GetROCSSPrimitiveValue());
|
||||
|
||||
if (!rv)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv->SetString(resultString);
|
||||
return CallQueryInterface(rv, aValue);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComputedDOMStyle::GetCounterReset(nsIDOMCSSValue** aValue)
|
||||
{
|
||||
@ -3301,6 +3424,42 @@ nsComputedDOMStyle::GetFrameBorderRectWidth(nscoord& aWidth)
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsComputedDOMStyle::GetFrameBoundsWidthForTransform(nscoord& aWidth)
|
||||
{
|
||||
// We need a frame to work with.
|
||||
if (!mInnerFrame) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
FlushPendingReflows();
|
||||
|
||||
// Check to see that we're transformed.
|
||||
if (!mInnerFrame->GetStyleDisplay()->HasTransform())
|
||||
return PR_FALSE;
|
||||
|
||||
aWidth = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).width;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsComputedDOMStyle::GetFrameBoundsHeightForTransform(nscoord& aHeight)
|
||||
{
|
||||
// We need a frame to work with.
|
||||
if (!mInnerFrame) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
FlushPendingReflows();
|
||||
|
||||
// Check to see that we're transformed.
|
||||
if (!mInnerFrame->GetStyleDisplay()->HasTransform())
|
||||
return PR_FALSE;
|
||||
|
||||
aHeight = nsDisplayTransform::GetFrameBoundsForTransform(mInnerFrame).height;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
|
||||
nsresult
|
||||
@ -4011,6 +4170,8 @@ nsComputedDOMStyle::GetQueryablePropertyMap(PRUint32* aLength)
|
||||
COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_topLeft, OutlineRadiusTopLeft),
|
||||
COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_topRight, OutlineRadiusTopRight),
|
||||
COMPUTED_STYLE_MAP_ENTRY(stack_sizing, StackSizing),
|
||||
COMPUTED_STYLE_MAP_ENTRY(_moz_transform, MozTransform),
|
||||
COMPUTED_STYLE_MAP_ENTRY(_moz_transform_origin, MozTransformOrigin),
|
||||
COMPUTED_STYLE_MAP_ENTRY(user_focus, UserFocus),
|
||||
COMPUTED_STYLE_MAP_ENTRY(user_input, UserInput),
|
||||
COMPUTED_STYLE_MAP_ENTRY(user_modify, UserModify),
|
||||
|
@ -271,6 +271,8 @@ private:
|
||||
nsresult GetOverflowY(nsIDOMCSSValue** aValue);
|
||||
nsresult GetPageBreakAfter(nsIDOMCSSValue** aValue);
|
||||
nsresult GetPageBreakBefore(nsIDOMCSSValue** aValue);
|
||||
nsresult GetMozTransform(nsIDOMCSSValue** aValue);
|
||||
nsresult GetMozTransformOrigin(nsIDOMCSSValue **aValue);
|
||||
|
||||
/* User interface properties */
|
||||
nsresult GetCursor(nsIDOMCSSValue** aValue);
|
||||
@ -374,6 +376,8 @@ private:
|
||||
|
||||
PRBool GetCBContentWidth(nscoord& aWidth);
|
||||
PRBool GetCBContentHeight(nscoord& aWidth);
|
||||
PRBool GetFrameBoundsWidthForTransform(nscoord &aWidth);
|
||||
PRBool GetFrameBoundsHeightForTransform(nscoord &aHeight);
|
||||
PRBool GetFrameBorderRectWidth(nscoord& aWidth);
|
||||
|
||||
struct ComputedStyleMapEntry
|
||||
|
@ -69,6 +69,8 @@
|
||||
#include "nsIStyleRule.h"
|
||||
#include "nsBidiUtils.h"
|
||||
#include "nsStyleStructInlines.h"
|
||||
#include "nsStyleTransformMatrix.h"
|
||||
#include "nsCSSKeywords.h"
|
||||
|
||||
/*
|
||||
* For storage of an |nsRuleNode|'s children in a PLDHashTable.
|
||||
@ -231,16 +233,27 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static nscoord CalcLength(const nsCSSValue& aValue,
|
||||
nsStyleContext* aStyleContext,
|
||||
nsPresContext* aPresContext,
|
||||
PRBool& aInherited)
|
||||
/* static */ nscoord
|
||||
nsRuleNode::CalcLength(const nsCSSValue& aValue,
|
||||
nsStyleContext* aStyleContext,
|
||||
nsPresContext* aPresContext,
|
||||
PRBool& aInherited)
|
||||
{
|
||||
NS_ASSERTION(aStyleContext, "Must have style data");
|
||||
|
||||
return CalcLengthWith(aValue, -1, nsnull, aStyleContext, aPresContext, aInherited);
|
||||
}
|
||||
|
||||
/* Inline helper function to redirect requests to CalcLength. */
|
||||
static inline nscoord CalcLength(const nsCSSValue& aValue,
|
||||
nsStyleContext* aStyleContext,
|
||||
nsPresContext* aPresContext,
|
||||
PRBool& aInherited)
|
||||
{
|
||||
return nsRuleNode::CalcLength(aValue, aStyleContext,
|
||||
aPresContext, aInherited);
|
||||
}
|
||||
|
||||
/* static */ nscoord
|
||||
nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
|
||||
const nsCSSValue& aValue)
|
||||
@ -264,6 +277,7 @@ nsRuleNode::CalcLengthWithInitialFont(nsPresContext* aPresContext,
|
||||
#define SETCOORD_INITIAL_AUTO 0x400
|
||||
#define SETCOORD_INITIAL_NONE 0x800
|
||||
#define SETCOORD_INITIAL_NORMAL 0x1000
|
||||
#define SETCOORD_INITIAL_HALF 0x2000
|
||||
|
||||
#define SETCOORD_LP (SETCOORD_LENGTH | SETCOORD_PERCENT)
|
||||
#define SETCOORD_LH (SETCOORD_LENGTH | SETCOORD_INHERIT)
|
||||
@ -343,12 +357,40 @@ static PRBool SetCoord(const nsCSSValue& aValue, nsStyleCoord& aCoord,
|
||||
(aValue.GetUnit() == eCSSUnit_Initial)) {
|
||||
aCoord.SetNormalValue();
|
||||
}
|
||||
else if (((aMask & SETCOORD_INITIAL_HALF) != 0) &&
|
||||
(aValue.GetUnit() == eCSSUnit_Initial)) {
|
||||
aCoord.SetPercentValue(0.5f);
|
||||
}
|
||||
else {
|
||||
result = PR_FALSE; // didn't set anything
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Given an enumerated value that represents a box position, converts it to
|
||||
* a float representing the percentage of the box it corresponds to. For
|
||||
* example, "center" becomes 0.5f.
|
||||
*
|
||||
* @param aEnumValue The enumerated value.
|
||||
* @return The float percent it corresponds to.
|
||||
*/
|
||||
static float GetFloatFromBoxPosition(PRInt32 aEnumValue)
|
||||
{
|
||||
switch (aEnumValue) {
|
||||
case NS_STYLE_BG_POSITION_LEFT:
|
||||
case NS_STYLE_BG_POSITION_TOP:
|
||||
return 0.0f;
|
||||
case NS_STYLE_BG_POSITION_RIGHT:
|
||||
case NS_STYLE_BG_POSITION_BOTTOM:
|
||||
return 1.0f;
|
||||
default:
|
||||
NS_NOTREACHED("unexpected value");
|
||||
// fall through
|
||||
case NS_STYLE_BG_POSITION_CENTER:
|
||||
return 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
static PRBool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
|
||||
nsPresContext* aPresContext, nsStyleContext *aContext,
|
||||
nscolor& aResult, PRBool& aInherited)
|
||||
@ -3078,6 +3120,38 @@ nsRuleNode::ComputeUIResetData(void* aStartStruct,
|
||||
COMPUTE_END_RESET(UIReset, ui)
|
||||
}
|
||||
|
||||
/* Given a -moz-transform token stream, accumulates them into an
|
||||
* nsStyleTransformMatrix
|
||||
*
|
||||
* @param aList The nsCSSValueList of arrays to read into transform functions.
|
||||
* @param aContext The style context to use for unit conversion.
|
||||
* @param aPresContext The presentation context to use for unit conversion
|
||||
* @param aInherited If the value is inherited, this is set to PR_TRUE.
|
||||
* @return An nsStyleTransformMatrix corresponding to the net transform.
|
||||
*/
|
||||
static nsStyleTransformMatrix ReadTransforms(const nsCSSValueList* aList,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
PRBool &aInherited)
|
||||
{
|
||||
nsStyleTransformMatrix result;
|
||||
|
||||
for (const nsCSSValueList* curr = aList; curr != nsnull; curr = curr->mNext) {
|
||||
const nsCSSValue &currElem = curr->mValue;
|
||||
NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
|
||||
"Stream should consist solely of functions!");
|
||||
NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1,
|
||||
"Incoming function is too short!");
|
||||
|
||||
/* Read in a single transform matrix, then accumulate it with the total. */
|
||||
nsStyleTransformMatrix currMatrix;
|
||||
currMatrix.SetToTransformFunction(currElem.GetArrayValue(), aContext,
|
||||
aPresContext);
|
||||
result *= currMatrix;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const void*
|
||||
nsRuleNode::ComputeDisplayData(void* aStartStruct,
|
||||
const nsRuleDataStruct& aData,
|
||||
@ -3330,6 +3404,79 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Convert the nsCSSValueList into an nsTArray<nsTransformFunction *>. */
|
||||
const nsCSSValueList *head = displayData.mTransform;
|
||||
|
||||
if (head != nsnull) {
|
||||
/* There is a chance that we will discover that
|
||||
* the transform property has been set to 'none,' 'initial,' or 'inherit.'
|
||||
* If so, process appropriately.
|
||||
*/
|
||||
|
||||
/* If it's 'none,' indicate that there are no transforms. */
|
||||
if (head->mValue.GetUnit() == eCSSUnit_None)
|
||||
display->mTransformPresent = PR_FALSE;
|
||||
|
||||
/* If we need to inherit, do so by making a full deep-copy. */
|
||||
else if (head->mValue.GetUnit() == eCSSUnit_Inherit) {
|
||||
display->mTransformPresent = parentDisplay->mTransformPresent;
|
||||
if (parentDisplay->mTransformPresent)
|
||||
display->mTransform = parentDisplay->mTransform;
|
||||
inherited = PR_TRUE;
|
||||
}
|
||||
/* If it's 'initial', then we reset to empty. */
|
||||
else if (head->mValue.GetUnit() == eCSSUnit_Initial)
|
||||
display->mTransformPresent = PR_FALSE;
|
||||
|
||||
/* Otherwise, we are looking at a list of CSS tokens. We'll read each of
|
||||
* them in as an array of nsTransformFunction objects, then will accumulate
|
||||
* them all together to form the final transform matrix.
|
||||
*/
|
||||
else {
|
||||
|
||||
display->mTransform =
|
||||
ReadTransforms(head, aContext, mPresContext, inherited);
|
||||
|
||||
/* Make sure to say that this data is valid! */
|
||||
display->mTransformPresent = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert -moz-transform-origin. */
|
||||
if (displayData.mTransformOrigin.mXValue.GetUnit() != eCSSUnit_Null ||
|
||||
displayData.mTransformOrigin.mXValue.GetUnit() != eCSSUnit_Null) {
|
||||
|
||||
/* If X coordinate is an enumerated type, handle it explicitly. */
|
||||
if (eCSSUnit_Enumerated == displayData.mTransformOrigin.mXValue.GetUnit())
|
||||
display->mTransformOrigin[0].SetPercentValue
|
||||
(GetFloatFromBoxPosition
|
||||
(displayData.mTransformOrigin.mXValue.GetIntValue()));
|
||||
else {
|
||||
/* Convert lengths, percents, and inherit. Default value is 50%. */
|
||||
PRBool result = SetCoord(displayData.mTransformOrigin.mXValue,
|
||||
display->mTransformOrigin[0],
|
||||
parentDisplay->mTransformOrigin[0],
|
||||
SETCOORD_LPH | SETCOORD_INITIAL_HALF,
|
||||
aContext, mPresContext, aInherited);
|
||||
NS_ASSERTION(result, "Malformed -moz-transform-origin parse!");
|
||||
}
|
||||
|
||||
/* If Y coordinate is an enumerated type, handle it explicitly. */
|
||||
if (eCSSUnit_Enumerated == displayData.mTransformOrigin.mYValue.GetUnit())
|
||||
display->mTransformOrigin[1].SetPercentValue
|
||||
(GetFloatFromBoxPosition
|
||||
(displayData.mTransformOrigin.mYValue.GetIntValue()));
|
||||
else {
|
||||
/* Convert lengths, percents, initial, inherit. */
|
||||
PRBool result = SetCoord(displayData.mTransformOrigin.mYValue,
|
||||
display->mTransformOrigin[1],
|
||||
parentDisplay->mTransformOrigin[1],
|
||||
SETCOORD_LPH | SETCOORD_INITIAL_HALF,
|
||||
aContext, mPresContext, aInherited);
|
||||
NS_ASSERTION(result, "Malformed -moz-transform-origin parse!");
|
||||
}
|
||||
}
|
||||
|
||||
COMPUTE_END_RESET(Display, display)
|
||||
}
|
||||
@ -3485,20 +3632,9 @@ nsRuleNode::ComputeBackgroundData(void* aStartStruct,
|
||||
bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_PERCENT;
|
||||
}
|
||||
else if (eCSSUnit_Enumerated == colorData.mBackPosition.mXValue.GetUnit()) {
|
||||
switch (colorData.mBackPosition.mXValue.GetIntValue()) {
|
||||
case NS_STYLE_BG_POSITION_LEFT:
|
||||
bg->mBackgroundXPosition.mFloat = 0.0f;
|
||||
break;
|
||||
case NS_STYLE_BG_POSITION_RIGHT:
|
||||
bg->mBackgroundXPosition.mFloat = 1.0f;
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("unexpected value");
|
||||
// fall through
|
||||
case NS_STYLE_BG_POSITION_CENTER:
|
||||
bg->mBackgroundXPosition.mFloat = 0.5f;
|
||||
break;
|
||||
}
|
||||
bg->mBackgroundXPosition.mFloat =
|
||||
GetFloatFromBoxPosition(colorData.mBackPosition.mXValue.GetIntValue());
|
||||
|
||||
bg->mBackgroundFlags |= NS_STYLE_BG_X_POSITION_PERCENT;
|
||||
bg->mBackgroundFlags &= ~NS_STYLE_BG_X_POSITION_LENGTH;
|
||||
}
|
||||
@ -3524,20 +3660,9 @@ nsRuleNode::ComputeBackgroundData(void* aStartStruct,
|
||||
bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_PERCENT;
|
||||
}
|
||||
else if (eCSSUnit_Enumerated == colorData.mBackPosition.mYValue.GetUnit()) {
|
||||
switch (colorData.mBackPosition.mYValue.GetIntValue()) {
|
||||
case NS_STYLE_BG_POSITION_TOP:
|
||||
bg->mBackgroundYPosition.mFloat = 0.0f;
|
||||
break;
|
||||
case NS_STYLE_BG_POSITION_BOTTOM:
|
||||
bg->mBackgroundYPosition.mFloat = 1.0f;
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("unexpected value");
|
||||
// fall through
|
||||
case NS_STYLE_BG_POSITION_CENTER:
|
||||
bg->mBackgroundYPosition.mFloat = 0.5f;
|
||||
break;
|
||||
}
|
||||
bg->mBackgroundYPosition.mFloat =
|
||||
GetFloatFromBoxPosition(colorData.mBackPosition.mYValue.GetIntValue());
|
||||
|
||||
bg->mBackgroundFlags |= NS_STYLE_BG_Y_POSITION_PERCENT;
|
||||
bg->mBackgroundFlags &= ~NS_STYLE_BG_Y_POSITION_LENGTH;
|
||||
}
|
||||
|
@ -742,6 +742,11 @@ public:
|
||||
// Expose this so media queries can use it
|
||||
static nscoord CalcLengthWithInitialFont(nsPresContext* aPresContext,
|
||||
const nsCSSValue& aValue);
|
||||
// Expose this so nsTransformFunctions can use it.
|
||||
static nscoord CalcLength(const nsCSSValue& aValue,
|
||||
nsStyleContext* aStyleContext,
|
||||
nsPresContext* aPresContext,
|
||||
PRBool& aInherited);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1236,6 +1236,9 @@ nsStyleDisplay::nsStyleDisplay()
|
||||
mClipFlags = NS_STYLE_CLIP_AUTO;
|
||||
mClip.SetRect(0,0,0,0);
|
||||
mOpacity = 1.0f;
|
||||
mTransformPresent = PR_FALSE; // No transform
|
||||
mTransformOrigin[0].SetPercentValue(0.5f); // Transform is centered on origin
|
||||
mTransformOrigin[1].SetPercentValue(0.5f);
|
||||
}
|
||||
|
||||
nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
|
||||
@ -1254,6 +1257,15 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
|
||||
mClipFlags = aSource.mClipFlags;
|
||||
mClip = aSource.mClip;
|
||||
mOpacity = aSource.mOpacity;
|
||||
|
||||
/* Copy over the transformation information. */
|
||||
mTransformPresent = aSource.mTransformPresent;
|
||||
if (mTransformPresent)
|
||||
mTransform = aSource.mTransform;
|
||||
|
||||
/* Copy over transform origin. */
|
||||
mTransformOrigin[0] = aSource.mTransformOrigin[0];
|
||||
mTransformOrigin[1] = aSource.mTransformOrigin[1];
|
||||
}
|
||||
|
||||
nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
|
||||
@ -1285,6 +1297,32 @@ nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
|
||||
if (mOpacity != aOther.mOpacity)
|
||||
NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
|
||||
|
||||
/* If we've added or removed the transform property, we need to reconstruct the frame to add
|
||||
* or remove the view object, and also to handle abs-pos and fixed-pos containers.
|
||||
*/
|
||||
if (mTransformPresent != aOther.mTransformPresent) {
|
||||
NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
|
||||
}
|
||||
else if (mTransformPresent) {
|
||||
/* Otherwise, if we've kept the property lying around and we already had a
|
||||
* transform, we need to see whether or not we've changed the transform.
|
||||
* If so, we need to do a reflow and a repaint. The reflow is to recompute
|
||||
* the overflow rect (which probably changed if the transform changed)
|
||||
* and to redraw within the bounds of that new overflow rect.
|
||||
*/
|
||||
if (mTransform != aOther.mTransform)
|
||||
NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame,
|
||||
nsChangeHint_RepaintFrame));
|
||||
|
||||
for (PRUint8 index = 0; index < 2; ++index)
|
||||
if (mTransformOrigin[index] != aOther.mTransformOrigin[index]) {
|
||||
NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame,
|
||||
nsChangeHint_RepaintFrame));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,7 @@
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "nsStyleTransformMatrix.h"
|
||||
|
||||
class nsIFrame;
|
||||
class imgIRequest;
|
||||
@ -886,7 +887,10 @@ struct nsStyleDisplay {
|
||||
PRUint8 mOverflowX; // [reset] see nsStyleConsts.h
|
||||
PRUint8 mOverflowY; // [reset] see nsStyleConsts.h
|
||||
PRUint8 mClipFlags; // [reset] see nsStyleConsts.h
|
||||
|
||||
PRPackedBool mTransformPresent; // [reset] Whether there is a -moz-transform.
|
||||
nsStyleTransformMatrix mTransform; // [reset] The stored transform matrix
|
||||
nsStyleCoord mTransformOrigin[2]; // [reset] percent, coord.
|
||||
|
||||
PRBool IsBlockInside() const {
|
||||
return NS_STYLE_DISPLAY_BLOCK == mDisplay ||
|
||||
NS_STYLE_DISPLAY_LIST_ITEM == mDisplay ||
|
||||
@ -918,8 +922,11 @@ struct nsStyleDisplay {
|
||||
PRBool IsAbsolutelyPositioned() const {return (NS_STYLE_POSITION_ABSOLUTE == mPosition) ||
|
||||
(NS_STYLE_POSITION_FIXED == mPosition);}
|
||||
|
||||
PRBool IsPositioned() const {return IsAbsolutelyPositioned() ||
|
||||
(NS_STYLE_POSITION_RELATIVE == mPosition);}
|
||||
/* Returns true if we're positioned or there's a transform in effect. */
|
||||
PRBool IsPositioned() const {
|
||||
return IsAbsolutelyPositioned() ||
|
||||
NS_STYLE_POSITION_RELATIVE == mPosition || mTransformPresent;
|
||||
}
|
||||
|
||||
PRBool IsScrollableOverflow() const {
|
||||
// mOverflowX and mOverflowY always match when one of them is
|
||||
@ -935,6 +942,11 @@ struct nsStyleDisplay {
|
||||
(mOverflowX == NS_STYLE_OVERFLOW_HIDDEN &&
|
||||
mOverflowY == NS_STYLE_OVERFLOW_HIDDEN);
|
||||
}
|
||||
|
||||
/* Returns whether the element has the -moz-transform property. */
|
||||
PRBool HasTransform() const {
|
||||
return mTransformPresent;
|
||||
}
|
||||
};
|
||||
|
||||
struct nsStyleTable {
|
||||
|
541
layout/style/nsStyleTransformMatrix.cpp
Normal file
541
layout/style/nsStyleTransformMatrix.cpp
Normal file
@ -0,0 +1,541 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
*
|
||||
* Contributor(s):
|
||||
* Keith Schwarz <kschwarz@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* A class used for intermediate representations of the -moz-transform property.
|
||||
*/
|
||||
|
||||
#include "nsStyleTransformMatrix.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsRuleNode.h"
|
||||
#include "nsCSSKeywords.h"
|
||||
#include <math.h>
|
||||
|
||||
/* Arguably, this loses precision, but it doesn't hurt! */
|
||||
const float kPi = 3.1415926535897932384626433f;
|
||||
const float kEpsilon = 0.0001f;
|
||||
|
||||
/* Computes tan(theta). For values of theta such that
|
||||
* tan(theta) is undefined or arbitrarily large, SafeTangent
|
||||
* returns a managably large or small value of the correct sign.
|
||||
*/
|
||||
static float SafeTangent(float aTheta)
|
||||
{
|
||||
/* We'll do this by computing sin and cos theta. If cos(theta) is
|
||||
* is too close to zero, we'll set it to some arbitrary epsilon value
|
||||
* that avoid float overflow or undefined result.
|
||||
*/
|
||||
float sinTheta = sin(aTheta);
|
||||
float cosTheta = cos(aTheta);
|
||||
|
||||
/* Bound cos(theta) to be in the range [-1, -epsilon) U (epsilon, 1] */
|
||||
if (cosTheta >= 0 && cosTheta < kEpsilon)
|
||||
cosTheta = kEpsilon;
|
||||
else if (cosTheta < 0 && cosTheta >= -kEpsilon)
|
||||
cosTheta = -kEpsilon;
|
||||
|
||||
return sinTheta / cosTheta;
|
||||
}
|
||||
|
||||
/* Converts an nsCSSValue containing an angle into an equivalent measure
|
||||
* of radians.
|
||||
*/
|
||||
static float CSSToRadians(const nsCSSValue &aValue)
|
||||
{
|
||||
NS_PRECONDITION(aValue.IsAngularUnit(),
|
||||
"Expected an angle, but didn't find one!");
|
||||
|
||||
switch (aValue.GetUnit()) {
|
||||
case eCSSUnit_Degree:
|
||||
/* 360deg = 2pi rad, so deg = pi / 180 rad */
|
||||
return aValue.GetFloatValue() * kPi / 180.0f;
|
||||
case eCSSUnit_Grad:
|
||||
/* 400grad = 2pi rad, so grad = pi / 200 rad */
|
||||
return aValue.GetFloatValue() * kPi / 200.0f;
|
||||
case eCSSUnit_Radian:
|
||||
/* Yay identity transforms! */
|
||||
return aValue.GetFloatValue();
|
||||
default:
|
||||
NS_NOTREACHED("Unexpected angular unit!");
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* Constructor sets the data to the identity matrix. */
|
||||
nsStyleTransformMatrix::nsStyleTransformMatrix()
|
||||
{
|
||||
SetToIdentity();
|
||||
}
|
||||
|
||||
/* SetToIdentity just fills in the appropriate values. */
|
||||
void nsStyleTransformMatrix::SetToIdentity()
|
||||
{
|
||||
/* Set the main matrix to the identity. */
|
||||
mMain[0] = 1.0f;
|
||||
mMain[1] = 0.0f;
|
||||
mMain[2] = 0.0f;
|
||||
mMain[3] = 1.0f;
|
||||
mDelta[0] = 0;
|
||||
mDelta[1] = 0;
|
||||
|
||||
/* Both translation matrices are zero. */
|
||||
mX[0] = 0.0f;
|
||||
mX[1] = 0.0f;
|
||||
mY[0] = 0.0f;
|
||||
mY[1] = 0.0f;
|
||||
}
|
||||
|
||||
/* Adds the constant translation to the scale factor translation components. */
|
||||
nscoord nsStyleTransformMatrix::GetXTranslation(const nsRect& aBounds) const
|
||||
{
|
||||
return nscoord(aBounds.width * mX[0] + aBounds.height * mY[0]) + mDelta[0];
|
||||
}
|
||||
nscoord nsStyleTransformMatrix::GetYTranslation(const nsRect& aBounds) const
|
||||
{
|
||||
return nscoord(aBounds.width * mX[1] + aBounds.height * mY[1]) + mDelta[1];
|
||||
}
|
||||
|
||||
/* GetThebesMatrix converts the stored matrix in a few steps. */
|
||||
gfxMatrix nsStyleTransformMatrix::GetThebesMatrix(const nsRect& aBounds,
|
||||
PRInt32 aScale) const
|
||||
{
|
||||
/* Compute the graphics matrix. Unfortunately, the gfxMatrix stores entries
|
||||
* as
|
||||
* | a b e |
|
||||
* | c d f |
|
||||
* | 0 0 1 |
|
||||
* But we store the matrix as
|
||||
* | a c e |
|
||||
* | b d f |
|
||||
* | 0 0 1 |
|
||||
* So, we'll have to be a bit clever about how we do the conversion.
|
||||
*
|
||||
* Also, we need to be sure to add to this matrices the following:
|
||||
*
|
||||
* | 0 0 dx1|
|
||||
* | 0 0 dx2| * width
|
||||
* | 0 0 0|
|
||||
*
|
||||
* | 0 0 dy1|
|
||||
* | 0 0 dy2| * height
|
||||
* | 0 0 0|
|
||||
*/
|
||||
|
||||
return gfxMatrix(mMain[0], mMain[2], mMain[1], mMain[3],
|
||||
NSAppUnitsToFloatPixels(GetXTranslation(aBounds), aScale),
|
||||
NSAppUnitsToFloatPixels(GetYTranslation(aBounds), aScale));
|
||||
}
|
||||
|
||||
/* Performs the matrix multiplication necessary to multiply the two matrices,
|
||||
* then hands back a reference to ourself.
|
||||
*/
|
||||
nsStyleTransformMatrix&
|
||||
nsStyleTransformMatrix::operator *= (const nsStyleTransformMatrix &aOther)
|
||||
{
|
||||
/* We'll buffer all of our results into a temporary storage location
|
||||
* during this operation since we don't want to overwrite the values of
|
||||
* the old matrix with the values of the new.
|
||||
*/
|
||||
float newMatrix[4];
|
||||
nscoord newDelta[2];
|
||||
float newX[2];
|
||||
float newY[2];
|
||||
|
||||
/* [aOther] [this]
|
||||
* |a1 c1 e1| |a0 c0 e0| |a0a1 + b0c1 c0a1 + d0c1 e0a1 + f0c1 + e1|
|
||||
* |b1 d1 f1|x|b0 d0 f0| = |a0b1 + b0d1 c0b1 + d0d1 e0b1 + f0d1 + f1|
|
||||
* |0 0 1 | | 0 0 1| | 0 0 1|
|
||||
*/
|
||||
newMatrix[0] = mMain[0] * aOther.mMain[0] + mMain[1] * aOther.mMain[2];
|
||||
newMatrix[1] = mMain[0] * aOther.mMain[1] + mMain[1] * aOther.mMain[3];
|
||||
newMatrix[2] = mMain[2] * aOther.mMain[0] + mMain[3] * aOther.mMain[2];
|
||||
newMatrix[3] = mMain[2] * aOther.mMain[1] + mMain[3] * aOther.mMain[3];
|
||||
newDelta[0] =
|
||||
NSCoordMultiply(mDelta[0], aOther.mMain[0]) +
|
||||
NSCoordMultiply(mDelta[1], aOther.mMain[2]) +
|
||||
aOther.mDelta[0];
|
||||
newDelta[1] =
|
||||
NSCoordMultiply(mDelta[0], aOther.mMain[1]) +
|
||||
NSCoordMultiply(mDelta[1], aOther.mMain[3]) +
|
||||
aOther.mDelta[1];
|
||||
|
||||
/* For consistent terminology, let u0, u1, v0, and v1 be the four transform
|
||||
* coordinates from the old matrix, and let x0, x1, y0, and y1 be the four
|
||||
* transform coordinates from the new matrix. Then the new transform
|
||||
* coordinates are:
|
||||
*
|
||||
* u0' = a1u0 + c1u1 + x0
|
||||
* u1' = b1u0 + d1u1 + x1
|
||||
* v0' = a1v0 + c1v1 + y0
|
||||
* v1' = b1v0 + d1v1 + y1
|
||||
*/
|
||||
newX[0] = aOther.mMain[0] * mX[0] + aOther.mMain[2] * mX[1] + aOther.mX[0];
|
||||
newX[1] = aOther.mMain[1] * mX[0] + aOther.mMain[3] * mX[1] + aOther.mX[1];
|
||||
newY[0] = aOther.mMain[0] * mY[0] + aOther.mMain[2] * mY[1] + aOther.mY[0];
|
||||
newY[1] = aOther.mMain[1] * mY[0] + aOther.mMain[3] * mY[1] + aOther.mY[1];
|
||||
|
||||
/* Now, write everything back in. */
|
||||
for (PRInt32 index = 0; index < 4; ++index)
|
||||
mMain[index] = newMatrix[index];
|
||||
for (PRInt32 index = 0; index < 2; ++index) {
|
||||
mDelta[index] = newDelta[index];
|
||||
mX[index] = newX[index];
|
||||
mY[index] = newY[index];
|
||||
}
|
||||
|
||||
/* As promised, return a reference to ourselves. */
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* op* is implemented in terms of op*=. */
|
||||
const nsStyleTransformMatrix
|
||||
nsStyleTransformMatrix::operator *(const nsStyleTransformMatrix &aOther) const
|
||||
{
|
||||
return nsStyleTransformMatrix(*this) *= aOther;
|
||||
}
|
||||
|
||||
/* Helper function to fill in an nscoord with the specified nsCSSValue. */
|
||||
static void SetCoordToValue(const nsCSSValue &aValue,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext, nscoord &aOut)
|
||||
{
|
||||
PRBool unused = PR_FALSE;
|
||||
aOut = nsRuleNode::CalcLength(aValue, aContext, aPresContext, unused);
|
||||
|
||||
NS_POSTCONDITION(!unused, "How did we inherit a value?");
|
||||
}
|
||||
|
||||
/* Helper function to process a matrix entry. */
|
||||
static void ProcessMatrix(float aMain[4], nscoord aDelta[2],
|
||||
float aX[2], float aY[2],
|
||||
const nsCSSValue::Array* aData,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 7, "Invalid array!");
|
||||
|
||||
/* Take the first four elements out of the array as floats and store
|
||||
* them in aMain.
|
||||
*/
|
||||
for (PRUint16 index = 1; index <= 4; ++index)
|
||||
aMain[index - 1] = aData->Item(index).GetFloatValue();
|
||||
|
||||
/* For the fifth element, if it's a percentage, store it in aX[0].
|
||||
* Otherwise, it's a length that needs to go in aDelta[0]
|
||||
*/
|
||||
if (aData->Item(5).GetUnit() == eCSSUnit_Percent)
|
||||
aX[0] = aData->Item(5).GetPercentValue();
|
||||
else
|
||||
SetCoordToValue(aData->Item(5), aContext, aPresContext, aDelta[0]);
|
||||
|
||||
/* For the final element, if it's a percentage, store it in aY[1].
|
||||
* Otherwise, it's a length that needs to go in aDelta[1].
|
||||
*/
|
||||
if (aData->Item(6).GetUnit() == eCSSUnit_Percent)
|
||||
aY[1] = aData->Item(5).GetPercentValue();
|
||||
else
|
||||
SetCoordToValue(aData->Item(6), aContext, aPresContext, aDelta[1]);
|
||||
}
|
||||
|
||||
/* Helper function to process a translatex function. */
|
||||
static void ProcessTranslateX(nscoord aDelta[2], float aX[2],
|
||||
const nsCSSValue::Array* aData,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
|
||||
|
||||
/* There are two cases. If we have a number, we want our matrix to look
|
||||
* like this:
|
||||
*
|
||||
* | 1 0 dx|
|
||||
* | 0 1 0|
|
||||
* | 0 0 1|
|
||||
* So E = value
|
||||
*
|
||||
* Otherwise, we might have a percentage, so we want to set the dX component
|
||||
* to the percent.
|
||||
*/
|
||||
if (aData->Item(1).GetUnit() != eCSSUnit_Percent)
|
||||
SetCoordToValue(aData->Item(1), aContext, aPresContext, aDelta[0]);
|
||||
else
|
||||
aX[0] = aData->Item(1).GetPercentValue();
|
||||
}
|
||||
|
||||
/* Helper function to process a translatey function. */
|
||||
static void ProcessTranslateY(nscoord aDelta[2], float aY[2],
|
||||
const nsCSSValue::Array* aData,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
|
||||
|
||||
/* There are two cases. If we have a number, we want our matrix to look
|
||||
* like this:
|
||||
*
|
||||
* | 1 0 0|
|
||||
* | 0 1 dy|
|
||||
* | 0 0 1|
|
||||
* So E = value
|
||||
*
|
||||
* Otherwise, we might have a percentage, so we want to set the dY component
|
||||
* to the percent.
|
||||
*/
|
||||
if (aData->Item(1).GetUnit() != eCSSUnit_Percent)
|
||||
SetCoordToValue(aData->Item(1), aContext, aPresContext, aDelta[1]);
|
||||
else
|
||||
aY[1] = aData->Item(1).GetPercentValue();
|
||||
}
|
||||
|
||||
/* Helper functiont to process a translate function. */
|
||||
static void ProcessTranslate(nscoord aDelta[2], float aX[2], float aY[2],
|
||||
const nsCSSValue::Array* aData,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!");
|
||||
|
||||
/* There are several cases to consider.
|
||||
* First, we might have one value, or we might have two. If we have
|
||||
* one, pretend we got two of the same value.
|
||||
* Next, the values might be lengths, or they might be percents. If they're
|
||||
* percents, store them in the dX and dY components. Otherwise, store them in
|
||||
* the main matrix.
|
||||
*/
|
||||
|
||||
const nsCSSValue &dx = aData->Item(1);
|
||||
const nsCSSValue &dy = (aData->Count() == 2 ? dx : aData->Item(2));
|
||||
|
||||
if (dx.GetUnit() == eCSSUnit_Percent)
|
||||
aX[0] = dx.GetPercentValue();
|
||||
else
|
||||
SetCoordToValue(dx, aContext, aPresContext, aDelta[0]);
|
||||
|
||||
if (dy.GetUnit() == eCSSUnit_Percent)
|
||||
aY[1] = dy.GetPercentValue();
|
||||
else
|
||||
SetCoordToValue(dy, aContext, aPresContext, aDelta[1]);
|
||||
}
|
||||
|
||||
/* Helper function to set up a scale matrix. */
|
||||
static void ProcessScaleHelper(float aXScale, float aYScale, float aMain[4])
|
||||
{
|
||||
/* We want our matrix to look like this:
|
||||
* | dx 0 0|
|
||||
* | 0 dy 0|
|
||||
* | 0 0 1|
|
||||
* So A = value
|
||||
*/
|
||||
aMain[0] = aXScale;
|
||||
aMain[3] = aYScale;
|
||||
}
|
||||
|
||||
/* Process a scalex function. */
|
||||
static void ProcessScaleX(float aMain[4], const nsCSSValue::Array* aData)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 2, "Bad array!");
|
||||
ProcessScaleHelper(aData->Item(1).GetFloatValue(), 1.0f, aMain);
|
||||
}
|
||||
|
||||
/* Process a scaley function. */
|
||||
static void ProcessScaleY(float aMain[4], const nsCSSValue::Array* aData)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 2, "Bad array!");
|
||||
ProcessScaleHelper(1.0f, aData->Item(1).GetFloatValue(), aMain);
|
||||
}
|
||||
|
||||
/* Process a scale function. */
|
||||
static void ProcessScale(float aMain[4], const nsCSSValue::Array* aData)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Bad array!");
|
||||
/* We either have one element or two. If we have one, it's for both X and Y.
|
||||
* Otherwise it's one for each.
|
||||
*/
|
||||
const nsCSSValue& scaleX = aData->Item(1);
|
||||
const nsCSSValue& scaleY = (aData->Count() == 2 ? scaleX :
|
||||
aData->Item(2));
|
||||
|
||||
ProcessScaleHelper(scaleX.GetFloatValue(),
|
||||
scaleY.GetFloatValue(), aMain);
|
||||
}
|
||||
|
||||
/* Helper function that, given a set of angles, constructs the appropriate
|
||||
* skew matrix.
|
||||
*/
|
||||
static void ProcessSkewHelper(float aXAngle, float aYAngle, float aMain[4])
|
||||
{
|
||||
/* We want our matrix to look like this:
|
||||
* | 1 tan(ThetaY) 0|
|
||||
* | tan(ThetaX) 1 0|
|
||||
* | 0 0 1|
|
||||
* However, to avoid infinte values, we'll use the SafeTangent function
|
||||
* instead of the C standard tan function.
|
||||
*/
|
||||
aMain[1] = SafeTangent(aXAngle);
|
||||
aMain[2] = SafeTangent(aYAngle);
|
||||
}
|
||||
|
||||
/* Function that converts a skewx transform into a matrix. */
|
||||
static void ProcessSkewX(float aMain[4], const nsCSSValue::Array* aData)
|
||||
{
|
||||
NS_ASSERTION(aData->Count() == 2, "Bad array!");
|
||||
ProcessSkewHelper(CSSToRadians(aData->Item(1)), 0.0f, aMain);
|
||||
}
|
||||
|
||||
/* Function that converts a skewy transform into a matrix. */
|
||||
static void ProcessSkewY(float aMain[4], const nsCSSValue::Array* aData)
|
||||
{
|
||||
NS_ASSERTION(aData->Count() == 2, "Bad array!");
|
||||
ProcessSkewHelper(0.0f, CSSToRadians(aData->Item(1)), aMain);
|
||||
}
|
||||
|
||||
/* Function that converts a skew transform into a matrix. */
|
||||
static void ProcessSkew(float aMain[4], const nsCSSValue::Array* aData)
|
||||
{
|
||||
NS_ASSERTION(aData->Count() == 2 || aData->Count() == 3, "Bad array!");
|
||||
|
||||
float xSkew = CSSToRadians(aData->Item(1));
|
||||
float ySkew = (aData->Count() == 2 ? xSkew : CSSToRadians(aData->Item(2)));
|
||||
|
||||
ProcessSkewHelper(xSkew, ySkew, aMain);
|
||||
}
|
||||
|
||||
/* Function that converts a rotate transform into a matrix. */
|
||||
static void ProcessRotate(float aMain[4], const nsCSSValue::Array* aData)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
|
||||
|
||||
/* We want our matrix to look like this:
|
||||
* | cos(theta) -sin(theta) 0|
|
||||
* | sin(theta) cos(theta) 0|
|
||||
* | 0 0 1|
|
||||
* However, there's a bit of a problem - our coordinate system has Y
|
||||
* increasing downward. Thus we will rotate by -theta
|
||||
* degrees. Thus:
|
||||
* A = cos(theta), B = -sin(theta), C = sin(theta), D = cos(theta)
|
||||
* (see http://www.w3.org/TR/SVG/coords.html#RotationDefined)
|
||||
*/
|
||||
float theta = CSSToRadians(aData->Item(1));
|
||||
float cosTheta = cos(theta);
|
||||
float sinTheta = sin(theta);
|
||||
|
||||
aMain[0] = cosTheta;
|
||||
aMain[1] = -sinTheta;
|
||||
aMain[2] = sinTheta;
|
||||
aMain[3] = cosTheta;
|
||||
}
|
||||
|
||||
/**
|
||||
* SetToTransformFunction is essentially a giant switch statement that fans
|
||||
* out to many smaller helper functions.
|
||||
*/
|
||||
void
|
||||
nsStyleTransformMatrix::SetToTransformFunction(const nsCSSValue::Array * aData,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext)
|
||||
{
|
||||
NS_PRECONDITION(aData, "Why did you want to get data from a null array?");
|
||||
NS_PRECONDITION(aContext, "Need a context for unit conversion!");
|
||||
NS_PRECONDITION(aPresContext, "Need a context for unit conversion!");
|
||||
|
||||
/* Reset the matrix to the identity so that each subfunction can just
|
||||
* worry about its own components.
|
||||
*/
|
||||
SetToIdentity();
|
||||
|
||||
/* Get the keyword for the transform. */
|
||||
nsAutoString keyword;
|
||||
aData->Item(0).GetStringValue(keyword);
|
||||
switch (nsCSSKeywords::LookupKeyword(keyword)) {
|
||||
case eCSSKeyword_translatex:
|
||||
ProcessTranslateX(mDelta, mX, aData, aContext, aPresContext);
|
||||
break;
|
||||
case eCSSKeyword_translatey:
|
||||
ProcessTranslateY(mDelta, mY, aData, aContext, aPresContext);
|
||||
break;
|
||||
case eCSSKeyword_translate:
|
||||
ProcessTranslate(mDelta, mX, mY, aData, aContext, aPresContext);
|
||||
break;
|
||||
case eCSSKeyword_scalex:
|
||||
ProcessScaleX(mMain, aData);
|
||||
break;
|
||||
case eCSSKeyword_scaley:
|
||||
ProcessScaleY(mMain, aData);
|
||||
break;
|
||||
case eCSSKeyword_scale:
|
||||
ProcessScale(mMain, aData);
|
||||
break;
|
||||
case eCSSKeyword_skewx:
|
||||
ProcessSkewX(mMain, aData);
|
||||
break;
|
||||
case eCSSKeyword_skewy:
|
||||
ProcessSkewY(mMain, aData);
|
||||
break;
|
||||
case eCSSKeyword_skew:
|
||||
ProcessSkew(mMain, aData);
|
||||
break;
|
||||
case eCSSKeyword_rotate:
|
||||
ProcessRotate(mMain, aData);
|
||||
break;
|
||||
case eCSSKeyword_matrix:
|
||||
ProcessMatrix(mMain, mDelta, mX, mY, aData, aContext, aPresContext);
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Unknown transform function!");
|
||||
}
|
||||
}
|
||||
|
||||
/* Does an element-by-element comparison and returns whether or not the
|
||||
* matrices are equal.
|
||||
*/
|
||||
PRBool
|
||||
nsStyleTransformMatrix::operator ==(const nsStyleTransformMatrix &aOther) const
|
||||
{
|
||||
for (PRInt32 index = 0; index < 4; ++index)
|
||||
if (mMain[index] != aOther.mMain[index])
|
||||
return PR_FALSE;
|
||||
|
||||
for (PRInt32 index = 0; index < 2; ++index)
|
||||
if (mDelta[index] != aOther.mDelta[index] ||
|
||||
mX[index] != aOther.mX[index] ||
|
||||
mY[index] != aOther.mY[index])
|
||||
return PR_FALSE;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
172
layout/style/nsStyleTransformMatrix.h
Normal file
172
layout/style/nsStyleTransformMatrix.h
Normal file
@ -0,0 +1,172 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
*
|
||||
* Contributor(s):
|
||||
* Keith Schwarz <kschwarz@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* A class representing three matrices that can be used for style transforms.
|
||||
*/
|
||||
|
||||
#ifndef nsStyleTransformMatrix_h_
|
||||
#define nsStyleTransformMatrix_h_
|
||||
|
||||
#include "nsCSSValue.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "nsRect.h"
|
||||
|
||||
/**
|
||||
* A class representing a style transformation matrix. The class actually
|
||||
* wraps three different matrices, a constant matrix and two matrices
|
||||
* whose values are scaled by the width and the height of the bounding
|
||||
* rectangle for the object to transform.
|
||||
*/
|
||||
class nsStyleContext;
|
||||
class nsPresContext;
|
||||
class nsStyleTransformMatrix
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor sets the matrix to the identity.
|
||||
*/
|
||||
nsStyleTransformMatrix();
|
||||
|
||||
/**
|
||||
* Given a frame's bounding rectangle, returns a gfxMatrix
|
||||
* corresponding to the transformation represented by this
|
||||
* matrix. The transformation takes points in the frame's
|
||||
* local space and converts them to points in the frame's
|
||||
* transformed space.
|
||||
*
|
||||
* @param aBounds The frame's bounding rectangle.
|
||||
* @param aFactor The number of app units per device pixel.
|
||||
* @return A Thebes matrix corresponding to the transform.
|
||||
*/
|
||||
gfxMatrix GetThebesMatrix(const nsRect& aBounds, PRInt32 aFactor) const;
|
||||
|
||||
/**
|
||||
* Multiplies this matrix by another matrix. The multiplication is
|
||||
* a post-multiplication, so A *= B updates this matrix to be BA.
|
||||
*
|
||||
* @param aOther The matrix to multiply this matrix by.
|
||||
* @return A reference to this matrix.
|
||||
*/
|
||||
nsStyleTransformMatrix& operator *= (const nsStyleTransformMatrix &aOther);
|
||||
|
||||
/**
|
||||
* Returns a new nsStyleTransformMatrix that's equal to this matrix
|
||||
* post-multiplied with another matrix.
|
||||
*
|
||||
* @param aOther The matrix to multiply this matrix by.
|
||||
* @return A new nsStyleTransformMatrix equal to this matrix postmultiplied
|
||||
* with the other matrix.
|
||||
*/
|
||||
const nsStyleTransformMatrix
|
||||
operator * (const nsStyleTransformMatrix &aOther) const;
|
||||
|
||||
/**
|
||||
* Given an nsCSSValue::Array* containing a -moz-transform function,
|
||||
* updates this matrix to hold the value of that function.
|
||||
*
|
||||
* @param aData The nsCSSValue::Array* containing the transform function.
|
||||
* @param aContext The style context, used for unit conversion.
|
||||
* @param aPresContext The presentation context, used for unit conversion.
|
||||
*/
|
||||
void SetToTransformFunction(const nsCSSValue::Array* aData,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext);
|
||||
|
||||
/**
|
||||
* Sets this matrix to be the identity matrix.
|
||||
*/
|
||||
void SetToIdentity();
|
||||
|
||||
/**
|
||||
* Returns the value of the entry at the 2x2 submatrix of the
|
||||
* transform matrix that defines the non-affine linear transform.
|
||||
* The order is given as
|
||||
* |elem[0] elem[2]|
|
||||
* |elem[1] elem[3]|
|
||||
*
|
||||
* @param aIndex The element index.
|
||||
* @return The value of the element at that index.
|
||||
*/
|
||||
float GetMainMatrixEntry(PRInt32 aIndex) const
|
||||
{
|
||||
NS_PRECONDITION(aIndex >= 0 && aIndex < 4, "Index out of bounds!");
|
||||
return mMain[aIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the X or Y translation component of the matrix,
|
||||
* given the specified bounds.
|
||||
*
|
||||
* @param aBounds The bounds of the element.
|
||||
* @return The value of the X or Ytranslation component.
|
||||
*/
|
||||
nscoord GetXTranslation(const nsRect& aBounds) const;
|
||||
nscoord GetYTranslation(const nsRect& aBounds) const;
|
||||
|
||||
/**
|
||||
* Returns whether the two matrices are equal or not.
|
||||
*
|
||||
* @param aOther The matrix to compare to.
|
||||
* @return Whether the two matrices are equal.
|
||||
*/
|
||||
PRBool operator== (const nsStyleTransformMatrix& aOther) const;
|
||||
PRBool operator!= (const nsStyleTransformMatrix& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
private:
|
||||
/* The three matrices look like this:
|
||||
* |mMain[0] mMain[2] mDelta[0]|
|
||||
* |mMain[1] mMain[3] mDelta[1]| <-- Constant matrix
|
||||
* | 0 0 1|
|
||||
*
|
||||
* | 0 0 mX[0]|
|
||||
* | 0 0 mX[1]| <-- Scaled by width of element
|
||||
* | 0 0 1|
|
||||
*
|
||||
* | 0 0 mY[0]|
|
||||
* | 0 0 mY[1]| <-- Scaled by height of element
|
||||
* | 0 0 1|
|
||||
*/
|
||||
float mMain[4];
|
||||
nscoord mDelta[2];
|
||||
float mX[2];
|
||||
float mY[2];
|
||||
};
|
||||
|
||||
#endif
|
@ -504,6 +504,31 @@ var gCSSProperties = {
|
||||
other_values: [ "1px", "3em" ],
|
||||
invalid_values: []
|
||||
},
|
||||
"-moz-transform": {
|
||||
domProp: "MozTransform",
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: [ "none" ],
|
||||
other_values: [ "translatex(1px)", "translatex(4em)", "translatex(-4px)", "translatex(3px)", "translatex(0px) translatex(1px) translatex(2px) translatex(3px) translatex(4px)", "translatey(4em)", "translate(3px)", "translate(10px, -3px)", "rotate(45deg)", "rotate(45grad)", "rotate(45rad)", "rotate(0)", "scalex(10)", "scaley(10)", "scale(10)", "scale(10, 20)", "skewx(30deg)", "skewx(0)", "skewy(0)", "skewx(30grad)", "skewx(30rad)", "skewy(30deg)", "skewy(30grad)", "skewy(30rad)", "matrix(1, 2, 3, 4, 5px, 6em)", "rotate(45deg) scale(2, 1)", "skewx(45deg) skewx(-50grad)", "translate(0, 0) scale(1, 1) skewx(0) skewy(0) matrix(1, 0, 0, 1, 0, 0)", "translatex(50%)", "translatey(50%)", "translate(50%)", "translate(3%, 5px)", "translate(5px, 3%)", "matrix(1, 2, 3, 4, 5px, 6%)", "matrix(1, 2, 3, 4, 5%, 6px)", "matrix(1, 2, 3, 4, 5%, 6%)"],
|
||||
invalid_values: ["1px", "#0000ff", "red", "auto", "translatex(1px 1px)", "translatex(translatex(1px))", "translatex(#0000ff)", "translatex(red)", "translatey()", "matrix(1, 2, 3, 4, 5, 6)", "matrix(1px, 2px, 3px, 4px, 5px, 6px)", "scale(150%)", "skewx(red)", "matrix(1%, 0, 0, 0, 0px, 0px)", "matrix(0, 1%, 2, 3, 4px,5px)", "matrix(0, 1, 2%, 3, 4px, 5px)", "matrix(0, 1, 2, 3%, 4%, 5%)"]
|
||||
},
|
||||
"-moz-transform-origin": {
|
||||
domProp: "MozTransformOrigin",
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
/* no subproperties */
|
||||
prerequisites: { "width": "10px", "height": "10px", "display": "block"},
|
||||
initial_values: [ "50% 50%", "center", "center center" ],
|
||||
other_values: [ "25% 25%", "5px 5px", "20% 3em", "0 0", "0in 1in",
|
||||
"top", "bottom","top left", "top right",
|
||||
"top center", "center left", "center right",
|
||||
"bottom left", "bottom right", "bottom center",
|
||||
"20% center", "5px center", "13in bottom",
|
||||
"left 50px", "right 13%", "center 40px"],
|
||||
invalid_values: ["red", "auto", "none", "0.5 0.5", "40px #0000ff",
|
||||
"border", "center red", "right diagonal",
|
||||
"#00ffff bottom"]
|
||||
},
|
||||
"-moz-stack-sizing": {
|
||||
domProp: "MozStackSizing",
|
||||
inherited: false,
|
||||
|
@ -305,6 +305,20 @@ nsSVGForeignObjectFrame::TransformPointFromOuterPx(const nsPoint &aIn,
|
||||
PresContext()->DevPixelsToAppUnits(NSToIntRound(y)));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
gfxMatrix
|
||||
nsSVGForeignObjectFrame::GetTransformMatrix(nsIFrame **aOutAncestor)
|
||||
{
|
||||
NS_PRECONDITION(aOutAncestor, "We need an ancestor to write to!");
|
||||
|
||||
/* Set the ancestor to be the outer frame. */
|
||||
*aOutAncestor = nsSVGUtils::GetOuterSVGFrame(this);
|
||||
NS_ASSERTION(*aOutAncestor, "How did we end up without an outer frame?");
|
||||
|
||||
/* Return the matrix back to the root, factoring in the x and y offsets. */
|
||||
nsCOMPtr<nsIDOMSVGMatrix> matrix = GetTMIncludingOffset();
|
||||
return nsSVGUtils::ConvertSVGMatrixToThebes(matrix);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsIFrame*)
|
||||
nsSVGForeignObjectFrame::GetFrameForPoint(const nsPoint &aPoint)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user