diff options
Diffstat (limited to 'WebCore/rendering/RenderLayer.cpp')
-rw-r--r-- | WebCore/rendering/RenderLayer.cpp | 332 |
1 files changed, 312 insertions, 20 deletions
diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp index 80e334a..8c7f23d 100644 --- a/WebCore/rendering/RenderLayer.cpp +++ b/WebCore/rendering/RenderLayer.cpp @@ -166,6 +166,7 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer) , m_hasVisibleContent(false) , m_visibleDescendantStatusDirty(false) , m_hasVisibleDescendant(false) + , m_isPaginated(false) , m_3DTransformedDescendantStatusDirty(true) , m_has3DTransformedDescendant(false) #if USE(ACCELERATED_COMPOSITING) @@ -308,7 +309,12 @@ void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags, IntPoint updateVisibilityStatus(); updateTransform(); - + + if (flags & UpdatePagination) + updatePagination(); + else + m_isPaginated = false; + if (m_hasVisibleContent) { RenderView* view = renderer()->view(); ASSERT(view); @@ -351,6 +357,9 @@ void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags, IntPoint flags &= ~IsCompositingUpdateRoot; #endif + if (renderer()->hasColumns()) + flags |= UpdatePagination; + for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) child->updateLayerPositions(flags, cachedOffset); @@ -449,6 +458,30 @@ TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavio return *m_transform; } +void RenderLayer::updatePagination() +{ + m_isPaginated = false; + if (isComposited() || !parent() || renderer()->isPositioned()) + return; // FIXME: We will have to deal with paginated compositing layers someday. + // FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though. + + if (isNormalFlowOnly()) { + m_isPaginated = parent()->renderer()->hasColumns(); + return; + } + + // If we're not normal flow, then we need to look for a multi-column object between us and our stacking context. + RenderLayer* ancestorStackingContext = stackingContext(); + for (RenderLayer* curr = parent(); curr; curr = curr->parent()) { + if (curr->renderer()->hasColumns()) { + m_isPaginated = true; + return; + } + if (curr == ancestorStackingContext || (curr->parent() && curr->parent()->renderer()->isPositioned())) + return; + } +} + void RenderLayer::setHasVisibleContent(bool b) { if (m_hasVisibleContent == b && !m_visibleContentStatusDirty) @@ -644,10 +677,14 @@ void RenderLayer::updateLayerPosition() localPoint += offset; } } else if (parent()) { - IntSize columnOffset; - parent()->renderer()->adjustForColumns(columnOffset, localPoint); - localPoint += columnOffset; - + if (isComposited()) { + // FIXME: Composited layers ignore pagination, so about the best we can do is make sure they're offset into the appropriate column. + // They won't split across columns properly. + IntSize columnOffset; + parent()->renderer()->adjustForColumns(columnOffset, localPoint); + localPoint += columnOffset; + } + IntSize scrollOffset = parent()->scrolledContentOffset(); localPoint -= scrollOffset; } @@ -2386,10 +2423,8 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, } // Now walk the sorted list of children with negative z-indices. - if (m_negZOrderList) - for (Vector<RenderLayer*>::iterator it = m_negZOrderList->begin(); it != m_negZOrderList->end(); ++it) - it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags); - + paintList(m_negZOrderList, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags); + // Now establish the appropriate clip and paint our child RenderObjects. if (shouldPaint && !clipRectToApply.isEmpty()) { // Begin transparency layers lazily now that we know we have to paint something. @@ -2425,15 +2460,11 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, } // Paint any child layers that have overflow. - if (m_normalFlowList) - for (Vector<RenderLayer*>::iterator it = m_normalFlowList->begin(); it != m_normalFlowList->end(); ++it) - it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags); - - // Now walk the sorted list of children with positive z-indices. - if (m_posZOrderList) - for (Vector<RenderLayer*>::iterator it = m_posZOrderList->begin(); it != m_posZOrderList->end(); ++it) - it[0]->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags); + paintList(m_normalFlowList, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags); + // Now walk the sorted list of children with positive z-indices. + paintList(m_posZOrderList, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags); + if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty()) { setClip(p, paintDirtyRect, damageRect); @@ -2453,6 +2484,119 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p, } } +void RenderLayer::paintList(Vector<RenderLayer*>* list, RenderLayer* rootLayer, GraphicsContext* p, + const IntRect& paintDirtyRect, PaintBehavior paintBehavior, + RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* overlapTestRequests, + PaintLayerFlags paintFlags) +{ + if (!list) + return; + + for (size_t i = 0; i < list->size(); ++i) { + RenderLayer* childLayer = list->at(i); + if (!childLayer->isPaginated()) + childLayer->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags); + else + paintPaginatedChildLayer(childLayer, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags); + } +} + +void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, GraphicsContext* context, + const IntRect& paintDirtyRect, PaintBehavior paintBehavior, + RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* overlapTestRequests, + PaintLayerFlags paintFlags) +{ + // We need to do multiple passes, breaking up our child layer into strips. + ASSERT(!renderer()->isPositioned()); + Vector<RenderLayer*> columnLayers; + RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContext(); + for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) { + if (curr->renderer()->hasColumns()) + columnLayers.append(curr); + if (curr == ancestorLayer || (curr->parent() && curr->parent()->renderer()->isPositioned())) + break; + } + + ASSERT(columnLayers.size()); + + paintChildLayerIntoColumns(childLayer, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags, columnLayers, columnLayers.size() - 1); +} + +void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLayer* rootLayer, GraphicsContext* context, + const IntRect& paintDirtyRect, PaintBehavior paintBehavior, + RenderObject* paintingRoot, RenderObject::OverlapTestRequestMap* overlapTestRequests, + PaintLayerFlags paintFlags, const Vector<RenderLayer*>& columnLayers, size_t colIndex) +{ + RenderBlock* columnBlock = toRenderBlock(columnLayers[colIndex]->renderer()); + + ASSERT(columnBlock && columnBlock->hasColumns()); + if (!columnBlock || !columnBlock->hasColumns()) + return; + + int layerX = 0; + int layerY = 0; + columnBlock->layer()->convertToLayerCoords(rootLayer, layerX, layerY); + + Vector<IntRect>* colRects = columnBlock->columnRects(); + unsigned colCount = colRects->size(); + int currYOffset = 0; + for (unsigned i = 0; i < colCount; i++) { + // For each rect, we clip to the rect, and then we adjust our coords. + IntRect colRect = colRects->at(i); + int currXOffset = colRect.x() - (columnBlock->borderLeft() + columnBlock->paddingLeft()); + colRect.move(layerX, layerY); + + IntRect localDirtyRect(paintDirtyRect); + localDirtyRect.intersect(colRect); + + if (!localDirtyRect.isEmpty()) { + context->save(); + + // Each strip pushes a clip, since column boxes are specified as being + // like overflow:hidden. + context->clip(colRect); + + if (!colIndex) { + // Apply a translation transform to change where the layer paints. + TransformationMatrix oldTransform; + bool oldHasTransform = childLayer->transform(); + if (oldHasTransform) + oldTransform = *childLayer->transform(); + TransformationMatrix newTransform(oldTransform); + newTransform.translateRight(currXOffset, currYOffset); + + childLayer->m_transform.set(new TransformationMatrix(newTransform)); + childLayer->paintLayer(rootLayer, context, localDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags); + if (oldHasTransform) + childLayer->m_transform.set(new TransformationMatrix(oldTransform)); + else + childLayer->m_transform.clear(); + } else { + // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space. + // This involves subtracting out the position of the layer in our current coordinate space. + int childX = 0; + int childY = 0; + columnLayers[colIndex - 1]->convertToLayerCoords(rootLayer, childX, childY); + TransformationMatrix transform; + transform.translateRight(childX + currXOffset, childY + currYOffset); + + // Apply the transform. + context->concatCTM(transform.toAffineTransform()); + + // Now do a paint with the root layer shifted to be the next multicol block. + paintChildLayerIntoColumns(childLayer, columnLayers[colIndex - 1], context, transform.inverse().mapRect(localDirtyRect), paintBehavior, + paintingRoot, overlapTestRequests, paintFlags, + columnLayers, colIndex - 1); + } + + context->restore(); + } + + // Move to the next position. + currYOffset -= colRect.height(); + } +} + static inline IntRect frameVisibleRect(RenderObject* renderer) { FrameView* frameView = renderer->document()->view(); @@ -2585,8 +2729,8 @@ static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, doubl // If zOffset is non-null (which indicates that the caller wants z offset information), // *zOffset on return is the z offset of the hit point relative to the containing flattening layer. RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, - const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform, - const HitTestingTransformState* transformState, double* zOffset) + const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform, + const HitTestingTransformState* transformState, double* zOffset) { // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate. @@ -2700,6 +2844,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont RenderLayer* candidateLayer = 0; // Begin by walking our list of positive layers from highest z-index down to the lowest z-index. +<<<<<<< HEAD if (m_posZOrderList) { for (int i = m_posZOrderList->size() - 1; i >= 0; --i) { #ifdef ANDROID_HITTEST_WITHSIZE @@ -2750,6 +2895,23 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont candidateLayer = hitLayer; } } +======= + RenderLayer* hitLayer = hitTestList(m_posZOrderList, rootLayer, request, result, hitTestRect, hitTestPoint, + localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); + if (hitLayer) { + if (!depthSortDescendants) + return hitLayer; + candidateLayer = hitLayer; + } + + // Now check our overflow objects. + hitLayer = hitTestList(m_normalFlowList, rootLayer, request, result, hitTestRect, hitTestPoint, + localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); + if (hitLayer) { + if (!depthSortDescendants) + return hitLayer; + candidateLayer = hitLayer; +>>>>>>> webkit.org at r60074 } // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. @@ -2784,6 +2946,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont } // Now check our negative z-index children. +<<<<<<< HEAD if (m_negZOrderList) { for (int i = m_negZOrderList->size() - 1; i >= 0; --i) { #ifdef ANDROID_HITTEST_WITHSIZE @@ -2807,8 +2970,16 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont candidateLayer = hitLayer; } } +======= + hitLayer = hitTestList(m_negZOrderList, rootLayer, request, result, hitTestRect, hitTestPoint, + localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); + if (hitLayer) { + if (!depthSortDescendants) + return hitLayer; + candidateLayer = hitLayer; +>>>>>>> webkit.org at r60074 } - + // If we found a layer, return. Child layers, and foreground always render in front of background. if (candidateLayer) return candidateLayer; @@ -2865,6 +3036,127 @@ bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& return true; } +RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* rootLayer, + const HitTestRequest& request, HitTestResult& result, + const IntRect& hitTestRect, const IntPoint& hitTestPoint, + const HitTestingTransformState* transformState, + double* zOffsetForDescendants, double* zOffset, + const HitTestingTransformState* unflattenedTransformState, + bool depthSortDescendants) +{ + if (!list) + return 0; + + RenderLayer* resultLayer = 0; + for (int i = list->size() - 1; i >= 0; --i) { + RenderLayer* childLayer = list->at(i); + RenderLayer* hitLayer = 0; + HitTestResult tempResult(result.point()); + if (childLayer->isPaginated()) + hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request, tempResult, hitTestRect, hitTestPoint, transformState, zOffsetForDescendants); + else + hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, transformState, zOffsetForDescendants); + if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState)) { + resultLayer = hitLayer; + result = tempResult; + if (!depthSortDescendants) + break; + } + } + + return resultLayer; +} + +RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, + const IntRect& hitTestRect, const IntPoint& hitTestPoint, const HitTestingTransformState* transformState, double* zOffset) +{ + ASSERT(!renderer()->isPositioned()); + Vector<RenderLayer*> columnLayers; + RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContext(); + for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) { + if (curr->renderer()->hasColumns()) + columnLayers.append(curr); + if (curr == ancestorLayer || (curr->parent() && curr->parent()->renderer()->isPositioned())) + break; + } + + ASSERT(columnLayers.size()); + return hitTestChildLayerColumns(childLayer, rootLayer, request, result, hitTestRect, hitTestPoint, transformState, zOffset, + columnLayers, columnLayers.size() - 1); +} + +RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, + const IntRect& hitTestRect, const IntPoint& hitTestPoint, const HitTestingTransformState* transformState, double* zOffset, + const Vector<RenderLayer*>& columnLayers, size_t columnIndex) +{ + RenderBlock* columnBlock = toRenderBlock(columnLayers[columnIndex]->renderer()); + + ASSERT(columnBlock && columnBlock->hasColumns()); + if (!columnBlock || !columnBlock->hasColumns()) + return 0; + + int layerX = 0; + int layerY = 0; + columnBlock->layer()->convertToLayerCoords(rootLayer, layerX, layerY); + + Vector<IntRect>* colRects = columnBlock->columnRects(); + int colCount = colRects->size(); + + // We have to go backwards from the last column to the first. + int left = columnBlock->borderLeft() + columnBlock->paddingLeft(); + int currYOffset = 0; + int i; + for (i = 0; i < colCount; i++) + currYOffset -= colRects->at(i).height(); + for (i = colCount - 1; i >= 0; i--) { + // For each rect, we clip to the rect, and then we adjust our coords. + IntRect colRect = colRects->at(i); + int currXOffset = colRect.x() - left; + currYOffset += colRect.height(); + colRect.move(layerX, layerY); + + IntRect localClipRect(hitTestRect); + localClipRect.intersect(colRect); + + if (!localClipRect.isEmpty() && localClipRect.contains(hitTestPoint)) { + RenderLayer* hitLayer = 0; + if (!columnIndex) { + // Apply a translation transform to change where the layer paints. + TransformationMatrix oldTransform; + bool oldHasTransform = childLayer->transform(); + if (oldHasTransform) + oldTransform = *childLayer->transform(); + TransformationMatrix newTransform(oldTransform); + newTransform.translateRight(currXOffset, currYOffset); + + childLayer->m_transform.set(new TransformationMatrix(newTransform)); + hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0], request, result, localClipRect, hitTestPoint, false, transformState, zOffset); + if (oldHasTransform) + childLayer->m_transform.set(new TransformationMatrix(oldTransform)); + else + childLayer->m_transform.clear(); + } else { + // Adjust the transform such that the renderer's upper left corner will be at (0,0) in user space. + // This involves subtracting out the position of the layer in our current coordinate space. + RenderLayer* nextLayer = columnLayers[columnIndex - 1]; + RefPtr<HitTestingTransformState> newTransformState = nextLayer->createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestPoint, transformState); + newTransformState->translate(currXOffset, currYOffset, HitTestingTransformState::AccumulateTransform); + IntPoint localPoint = roundedIntPoint(newTransformState->mappedPoint()); + IntRect localHitTestRect = newTransformState->mappedQuad().enclosingBoundingBox(); + newTransformState->flatten(); + + hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[columnIndex - 1], request, result, localHitTestRect, localPoint, + newTransformState.get(), zOffset, columnLayers, columnIndex - 1); + } + + if (hitLayer) + return hitLayer; + } + } + + return 0; +} + void RenderLayer::updateClipRects(const RenderLayer* rootLayer) { if (m_clipRects) { |