Bug 772679. RestrictToLayerPixels needs to accurately convert between appunits scroll offsets and ThebesLayer pixel coordinates. r=tnikkel

Change GetThebesLayerResolutionForFrame to GetThebesLayerScaleForFrame,
which just returns a scale. Ensure that the scale is as accurate as possible
even if dedicated layers for scrolled content (or any layers at all) have not
been created yet, by taking into account transforms that have not yet
generated layers. This makes the decisions made by
nsGfxScrollFrameInner::ScrollToImpl independent of whether there is
currently an active layer for the scrolled content (or much more nearly so).
In nsGfxScrollFrameInner::ScrollToImpl, do not use the current internal
fractional offset of the ThebesLayer, which is in a mostly unrelated
coordinate space to our scroll positions. Instead, just try to make sure
that the previous and next scroll position differ by a whole number of
layer pixels.
This commit is contained in:
Robert O'Callahan
2012-08-05 00:26:38 +12:00
parent 42be4855ad
commit 4987fd45b3
4 changed files with 97 additions and 87 deletions

View File

@@ -2505,44 +2505,50 @@ FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey)
return nullptr;
}
bool
FrameLayerBuilder::GetThebesLayerResolutionForFrame(nsIFrame* aFrame,
double* aXres, double* aYres,
gfxPoint* aPoint)
static gfxSize
PredictScaleForContent(nsIFrame* aFrame, nsIFrame* aAncestorWithScale,
const gfxSize& aScale)
{
nsTArray<DisplayItemData> *array = GetDisplayItemDataArrayForFrame(aFrame);
if (array) {
for (PRUint32 i = 0; i < array->Length(); ++i) {
Layer* layer = array->ElementAt(i).mLayer;
if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
ThebesDisplayItemLayerUserData* data =
static_cast<ThebesDisplayItemLayerUserData*>
(layer->GetUserData(&gThebesDisplayItemLayerUserData));
*aXres = data->mXScale;
*aYres = data->mYScale;
*aPoint = data->mActiveScrolledRootPosition;
return true;
gfx3DMatrix transform =
gfx3DMatrix::ScalingMatrix(aScale.width, aScale.height, 1.0);
// aTransform is applied first, then the scale is applied to the result
transform = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestorWithScale)*transform;
gfxMatrix transform2d;
if (transform.CanDraw2D(&transform2d)) {
return transform2d.ScaleFactors(true);
}
return gfxSize(1.0, 1.0);
}
gfxSize
FrameLayerBuilder::GetThebesLayerScaleForFrame(nsIFrame* aFrame)
{
nsIFrame* last;
for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
last = f;
if (f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) {
nsTArray<DisplayItemData>* array = GetDisplayItemDataArrayForFrame(f);
NS_ASSERTION(array, "Must have display item data for container");
for (PRUint32 i = 0; i < array->Length(); ++i) {
Layer* layer = array->ElementAt(i).mLayer;
ContainerLayer* container = layer->AsContainerLayer();
if (!container) {
continue;
}
for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) {
ThebesDisplayItemLayerUserData* data =
static_cast<ThebesDisplayItemLayerUserData*>
(l->GetUserData(&gThebesDisplayItemLayerUserData));
if (data) {
return PredictScaleForContent(aFrame, f, gfxSize(data->mXScale, data->mYScale));
}
}
}
}
}
nsIFrame::ChildListIterator lists(aFrame);
for (; !lists.IsDone(); lists.Next()) {
if (lists.CurrentID() == nsIFrame::kPopupList ||
lists.CurrentID() == nsIFrame::kSelectPopupList) {
continue;
}
nsFrameList::Enumerator childFrames(lists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
if (GetThebesLayerResolutionForFrame(childFrames.get(),
aXres, aYres, aPoint)) {
return true;
}
}
}
return false;
return PredictScaleForContent(aFrame, last,
last->PresContext()->PresShell()->GetResolution());
}
#ifdef MOZ_DUMP_PAINTING