Bug 1101627 - Add touch action regions. r=kats

This commit is contained in:
Kushan Joshi 2015-03-24 09:13:24 -04:00
parent bdd3d99afa
commit a3c4b7a023
10 changed files with 180 additions and 44 deletions

View File

@ -912,12 +912,18 @@ struct ParamTraits<mozilla::layers::EventRegions>
{
WriteParam(aMsg, aParam.mHitRegion);
WriteParam(aMsg, aParam.mDispatchToContentHitRegion);
WriteParam(aMsg, aParam.mNoActionRegion);
WriteParam(aMsg, aParam.mHorizontalPanRegion);
WriteParam(aMsg, aParam.mVerticalPanRegion);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return (ReadParam(aMsg, aIter, &aResult->mHitRegion) &&
ReadParam(aMsg, aIter, &aResult->mDispatchToContentHitRegion));
ReadParam(aMsg, aIter, &aResult->mDispatchToContentHitRegion) &&
ReadParam(aMsg, aIter, &aResult->mNoActionRegion) &&
ReadParam(aMsg, aIter, &aResult->mHorizontalPanRegion) &&
ReadParam(aMsg, aIter, &aResult->mVerticalPanRegion));
}
};

View File

@ -152,6 +152,15 @@ AppendToString(std::stringstream& aStream, const EventRegions& e,
if (!e.mDispatchToContentHitRegion.IsEmpty()) {
AppendToString(aStream, e.mDispatchToContentHitRegion, " dispatchtocontentregion=", "");
}
if (!e.mNoActionRegion.IsEmpty()) {
AppendToString(aStream, e.mNoActionRegion, " NoActionRegion=","");
}
if (!e.mHorizontalPanRegion.IsEmpty()) {
AppendToString(aStream, e.mHorizontalPanRegion, " HorizontalPanRegion=", "");
}
if (!e.mVerticalPanRegion.IsEmpty()) {
AppendToString(aStream, e.mVerticalPanRegion, " VerticalPanRegion=", "");
}
aStream << "}" << sfx;
}

View File

@ -158,9 +158,24 @@ enum class ScaleMode : int8_t {
};
struct EventRegions {
// The hit region for a layer contains all areas on the layer that are
// sensitive to events. This region is an over-approximation and may
// contain regions that are not actually sensitive, but any such regions
// will be included in the mDispatchToContentHitRegion.
nsIntRegion mHitRegion;
// The mDispatchToContentHitRegion for a layer contains all areas for
// which the main-thread must be consulted before responding to events.
// This region will be a subregion of mHitRegion.
nsIntRegion mDispatchToContentHitRegion;
// The following regions represent the touch-action areas of this layer.
// All of these regions are approximations to the true region, but any
// variance between the approximation and the true region is guaranteed
// to be included in the mDispatchToContentHitRegion.
nsIntRegion mNoActionRegion;
nsIntRegion mHorizontalPanRegion;
nsIntRegion mVerticalPanRegion;
EventRegions()
{
}

View File

@ -385,6 +385,9 @@ public:
mHitRegion.Or(mHitRegion, aEventRegions->HitRegion());
mMaybeHitRegion.Or(mMaybeHitRegion, aEventRegions->MaybeHitRegion());
mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, aEventRegions->DispatchToContentHitRegion());
mNoActionRegion.Or(mNoActionRegion, aEventRegions->NoActionRegion());
mHorizontalPanRegion.Or(mHorizontalPanRegion, aEventRegions->HorizontalPanRegion());
mVerticalPanRegion.Or(mVerticalPanRegion, aEventRegions->VerticalPanRegion());
}
/**
@ -433,6 +436,27 @@ public:
* The dispatch-to-content hit region for this PaintedLayer.
*/
nsRegion mDispatchToContentHitRegion;
/**
* The region for this PaintedLayer that is sensitive to events
* but disallows panning and zooming. This is an approximation
* and any deviation from the true region will be part of the
* mDispatchToContentHitRegion.
*/
nsRegion mNoActionRegion;
/**
* The region for this PaintedLayer that is sensitive to events and
* allows horizontal panning but not zooming. This is an approximation
* and any deviation from the true region will be part of the
* mDispatchToContentHitRegion.
*/
nsRegion mHorizontalPanRegion;
/**
* The region for this PaintedLayer that is sensitive to events and
* allows vertical panning but not zooming. This is an approximation
* and any deviation from the true region will be part of the
* mDispatchToContentHitRegion.
*/
nsRegion mVerticalPanRegion;
/**
* The "active scrolled root" for all content in the layer. Must
* be non-null; all content in a PaintedLayer must have the same
@ -2409,24 +2433,38 @@ ContainerState::PopPaintedLayerData()
containingPaintedLayerData->mMaybeHitRegion.Or(
containingPaintedLayerData->mMaybeHitRegion, rect);
}
if (!data->mHitRegion.GetBounds().IsEmpty()) {
// Our definitely-hit region must go to the maybe-hit-region since
// this function is an approximation.
Matrix4x4 matrix = nsLayoutUtils::GetTransformToAncestor(
mContainerReferenceFrame, containingPaintedLayerData->mReferenceFrame);
Matrix matrix2D;
bool isPrecise = matrix.Is2D(&matrix2D) && !matrix2D.HasNonAxisAlignedTransform();
nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
mContainerReferenceFrame,
data->mHitRegion.GetBounds(),
containingPaintedLayerData->mReferenceFrame);
nsRegion* dest = isPrecise ? &containingPaintedLayerData->mHitRegion
: &containingPaintedLayerData->mMaybeHitRegion;
dest->Or(*dest, rect);
}
nsLayoutUtils::TransformToAncestorAndCombineRegions(
data->mHitRegion.GetBounds(),
mContainerReferenceFrame,
containingPaintedLayerData->mReferenceFrame,
&containingPaintedLayerData->mHitRegion,
&containingPaintedLayerData->mMaybeHitRegion);
nsLayoutUtils::TransformToAncestorAndCombineRegions(
data->mNoActionRegion.GetBounds(),
mContainerReferenceFrame,
containingPaintedLayerData->mReferenceFrame,
&containingPaintedLayerData->mNoActionRegion,
&containingPaintedLayerData->mDispatchToContentHitRegion);
nsLayoutUtils::TransformToAncestorAndCombineRegions(
data->mHorizontalPanRegion.GetBounds(),
mContainerReferenceFrame,
containingPaintedLayerData->mReferenceFrame,
&containingPaintedLayerData->mHorizontalPanRegion,
&containingPaintedLayerData->mDispatchToContentHitRegion);
nsLayoutUtils::TransformToAncestorAndCombineRegions(
data->mVerticalPanRegion.GetBounds(),
mContainerReferenceFrame,
containingPaintedLayerData->mReferenceFrame,
&containingPaintedLayerData->mVerticalPanRegion,
&containingPaintedLayerData->mDispatchToContentHitRegion);
} else {
EventRegions regions;
regions.mHitRegion = ScaleRegionToOutsidePixels(data->mHitRegion);
regions.mNoActionRegion = ScaleRegionToOutsidePixels(data->mNoActionRegion);
regions.mHorizontalPanRegion = ScaleRegionToOutsidePixels(data->mHorizontalPanRegion);
regions.mVerticalPanRegion = ScaleRegionToOutsidePixels(data->mVerticalPanRegion);
// Points whose hit-region status we're not sure about need to be dispatched
// to the content thread. If a point is in both maybeHitRegion and hitRegion
// then it's not a "maybe" any more, and doesn't go into the dispatch-to-
@ -2440,6 +2478,9 @@ ContainerState::PopPaintedLayerData()
nsIntPoint translation = -GetTranslationForPaintedLayer(data->mLayer);
regions.mHitRegion.MoveBy(translation);
regions.mDispatchToContentHitRegion.MoveBy(translation);
regions.mNoActionRegion.MoveBy(translation);
regions.mHorizontalPanRegion.MoveBy(translation);
regions.mVerticalPanRegion.MoveBy(translation);
layer->SetEventRegions(regions);
}

View File

@ -3229,6 +3229,20 @@ nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
if (aBuilder->GetAncestorHasApzAwareEventHandler()) {
mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, borderBox);
}
// Touch action region
uint32_t touchAction = nsLayoutUtils::GetTouchActionFromFrame(aFrame);
if (touchAction & NS_STYLE_TOUCH_ACTION_NONE) {
mNoActionRegion.Or(mNoActionRegion, borderBox);
} else {
if ((touchAction & NS_STYLE_TOUCH_ACTION_PAN_X)) {
mHorizontalPanRegion.Or(mHorizontalPanRegion, borderBox);
}
if ((touchAction & NS_STYLE_TOUCH_ACTION_PAN_Y)) {
mVerticalPanRegion.Or(mVerticalPanRegion, borderBox);
}
}
}
void

View File

@ -2711,6 +2711,9 @@ public:
const nsRegion& HitRegion() { return mHitRegion; }
const nsRegion& MaybeHitRegion() { return mMaybeHitRegion; }
const nsRegion& DispatchToContentHitRegion() { return mDispatchToContentHitRegion; }
const nsRegion& NoActionRegion() { return mNoActionRegion; }
const nsRegion& HorizontalPanRegion() { return mHorizontalPanRegion; }
const nsRegion& VerticalPanRegion() { return mVerticalPanRegion; }
virtual void WriteDebugInfo(std::stringstream& aStream) override;
@ -2724,6 +2727,15 @@ private:
// These are points that need to be dispatched to the content thread for
// resolution. Always contained in the union of mHitRegion and mMaybeHitRegion.
nsRegion mDispatchToContentHitRegion;
// These are points where panning is disabled, as determined by the touch-action
// property. Always contained in the union of mHitRegion and mMaybeHitRegion.
nsRegion mNoActionRegion;
// These are points where panning is horizontal, as determined by the touch-action
// property. Always contained in the union of mHitRegion and mMaybeHitRegion.
nsRegion mHorizontalPanRegion;
// These are points where panning is vertical, as determined by the touch-action
// property. Always contained in the union of mHitRegion and mMaybeHitRegion.
nsRegion mVerticalPanRegion;
};
/**

View File

@ -8005,3 +8005,50 @@ nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(nsIPresShell* aShell)
}
return false;
}
/* static */ uint32_t
nsLayoutUtils::GetTouchActionFromFrame(nsIFrame* aFrame)
{
// If aFrame is null then return default value
if (!aFrame) {
return NS_STYLE_TOUCH_ACTION_AUTO;
}
// The touch-action CSS property applies to: all elements except:
// non-replaced inline elements, table rows, row groups, table columns, and column groups
bool isNonReplacedInlineElement = aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
if (isNonReplacedInlineElement) {
return NS_STYLE_TOUCH_ACTION_AUTO;
}
const nsStyleDisplay* disp = aFrame->StyleDisplay();
bool isTableElement = disp->IsInnerTableStyle() &&
disp->mDisplay != NS_STYLE_DISPLAY_TABLE_CELL &&
disp->mDisplay != NS_STYLE_DISPLAY_TABLE_CAPTION;
if (isTableElement) {
return NS_STYLE_TOUCH_ACTION_AUTO;
}
return disp->mTouchAction;
}
/* static */ void
nsLayoutUtils::TransformToAncestorAndCombineRegions(
const nsRect& aBounds,
nsIFrame* aFrame,
const nsIFrame* aAncestorFrame,
nsRegion* aPreciseTargetDest,
nsRegion* aImpreciseTargetDest)
{
if (aBounds.IsEmpty()) {
return;
}
Matrix4x4 matrix = GetTransformToAncestor(aFrame, aAncestorFrame);
Matrix matrix2D;
bool isPrecise = (matrix.Is2D(&matrix2D)
&& !matrix2D.HasNonAxisAlignedTransform());
nsRect transformed = TransformFrameRectToAncestor(
aFrame, aBounds, aAncestorFrame);
nsRegion* dest = isPrecise ? aPreciseTargetDest : aImpreciseTargetDest;
dest->OrWith(transformed);
}

View File

@ -2417,6 +2417,25 @@ public:
AssertTreeOnlyEmptyNextInFlows(nsIFrame *aSubtreeRoot);
#endif
/**
* Helper method to get touch action behaviour from the frame
*/
static uint32_t
GetTouchActionFromFrame(nsIFrame* aFrame);
/**
* Helper method to transform |aBounds| from aFrame to aAncestorFrame,
* and combine it with |aPreciseTargetDest| if it is axis-aligned, or
* combine it with |aImpreciseTargetDest| if not.
*/
static void
TransformToAncestorAndCombineRegions(
const nsRect& aBounds,
nsIFrame* aFrame,
const nsIFrame* aAncestorFrame,
nsRegion* aPreciseTargetDest,
nsRegion* aImpreciseTargetDest);
/**
* Determine if aImageFrame (which is an nsImageFrame, nsImageControlFrame, or
* nsSVGImageFrame) is visible or close to being visible via scrolling and

View File

@ -15,32 +15,6 @@
namespace mozilla {
namespace widget {
uint32_t
ContentHelper::GetTouchActionFromFrame(nsIFrame* aFrame)
{
// If aFrame is null then return default value
if (!aFrame) {
return NS_STYLE_TOUCH_ACTION_AUTO;
}
// The touch-action CSS property applies to: all elements except:
// non-replaced inline elements, table rows, row groups, table columns, and column groups
bool isNonReplacedInlineElement = aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
if (isNonReplacedInlineElement) {
return NS_STYLE_TOUCH_ACTION_AUTO;
}
const nsStyleDisplay* disp = aFrame->StyleDisplay();
bool isTableElement = disp->IsInnerTableStyle() &&
disp->mDisplay != NS_STYLE_DISPLAY_TABLE_CELL &&
disp->mDisplay != NS_STYLE_DISPLAY_TABLE_CAPTION;
if (isTableElement) {
return NS_STYLE_TOUCH_ACTION_AUTO;
}
return disp->mTouchAction;
}
void
ContentHelper::UpdateAllowedBehavior(uint32_t aTouchActionValue, bool aConsiderPanning, TouchBehaviorFlags& aOutBehavior)
{
@ -103,7 +77,7 @@ ContentHelper::GetAllowedTouchBehavior(nsIWidget* aWidget, const LayoutDeviceInt
AllowedTouchBehavior::PINCH_ZOOM | AllowedTouchBehavior::DOUBLE_TAP_ZOOM;
for (nsIFrame *frame = target; frame && frame->GetContent() && behavior; frame = frame->GetParent()) {
UpdateAllowedBehavior(GetTouchActionFromFrame(frame), considerPanning, behavior);
UpdateAllowedBehavior(nsLayoutUtils::GetTouchActionFromFrame(frame), considerPanning, behavior);
if (frame == nearestScrollableFrame) {
// We met the scrollable element, after it we shouldn't consider touch-action

View File

@ -22,7 +22,6 @@ class ContentHelper
typedef uint32_t TouchBehaviorFlags;
private:
static uint32_t GetTouchActionFromFrame(nsIFrame* aFrame);
static void UpdateAllowedBehavior(uint32_t aTouchActionValue, bool aConsiderPanning, TouchBehaviorFlags& aOutBehavior);
public: