PassRefPtr<PictureSnapshot> PictureSnapshot::load(const Vector<RefPtr<TilePictureStream>>& tiles) { ASSERT(!tiles.isEmpty()); Vector<RefPtr<SkPicture>> pictures; pictures.reserveCapacity(tiles.size()); FloatRect unionRect; for (const auto& tileStream : tiles) { SkMemoryStream stream(tileStream->data.begin(), tileStream->data.size()); RefPtr<SkPicture> picture = adoptRef(SkPicture::CreateFromStream(&stream, decodeBitmap)); if (!picture) return nullptr; FloatRect cullRect(picture->cullRect()); cullRect.moveBy(tileStream->layerOffset); unionRect.unite(cullRect); pictures.append(picture); } if (tiles.size() == 1) return adoptRef(new PictureSnapshot(pictures[0])); SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(unionRect.width(), unionRect.height(), 0, 0); for (size_t i = 0; i < pictures.size(); ++i) { canvas->save(); canvas->translate(tiles[i]->layerOffset.x() - unionRect.x(), tiles[i]->layerOffset.y() - unionRect.y()); pictures[i]->playback(canvas, 0); canvas->restore(); } return adoptRef(new PictureSnapshot(adoptRef(recorder.endRecordingAsPicture()))); }
void PaintLayerPainter::paintOverflowControlsForFragments(const PaintLayerFragments& layerFragments, GraphicsContext& context, const PaintLayerPaintingInfo& localPaintingInfo, PaintLayerFlags paintFlags) { bool needsScope = layerFragments.size() > 1; for (auto& fragment : layerFragments) { Optional<ScopeRecorder> scopeRecorder; if (needsScope) scopeRecorder.emplace(context); Optional<LayerClipRecorder> clipRecorder; if (needsToClip(localPaintingInfo, fragment.backgroundRect)) clipRecorder.emplace(context, *m_paintLayer.layoutObject(), DisplayItem::ClipLayerOverflowControls, fragment.backgroundRect, &localPaintingInfo, fragment.paginationOffset, paintFlags); if (PaintLayerScrollableArea* scrollableArea = m_paintLayer.scrollableArea()) { CullRect cullRect(pixelSnappedIntRect(fragment.backgroundRect.rect())); ScrollableAreaPainter(*scrollableArea).paintOverflowControls(context, roundedIntPoint(toPoint(fragment.layerBounds.location() - m_paintLayer.layoutBoxLocation())), cullRect, true); } } }
bool LineBoxList::hitTest(LineLayoutBoxModel layoutObject, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) const { if (hitTestAction != HitTestForeground) return false; ASSERT(layoutObject.isLayoutBlock() || (layoutObject.isLayoutInline() && layoutObject.hasLayer())); // The only way an inline could hit test like this is if it has a layer. // If we have no lines then we have no work to do. if (!firstLineBox()) return false; LayoutPoint point = locationInContainer.point(); CullRect cullRect(firstLineBox()->isHorizontal() ? IntRect(point.x(), point.y() - locationInContainer.topPadding(), 1, locationInContainer.topPadding() + locationInContainer.bottomPadding() + 1) : IntRect(point.x() - locationInContainer.leftPadding(), point.y(), locationInContainer.rightPadding() + locationInContainer.leftPadding() + 1, 1)); if (!anyLineIntersectsRect(layoutObject, cullRect, accumulatedOffset)) return false; // See if our root lines contain the point. If so, then we hit test // them further. Note that boxes can easily overlap, so we can't make any assumptions // based off positions of our first line box or our last line box. for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevLineBox()) { RootInlineBox& root = curr->root(); if (rangeIntersectsRect(layoutObject, curr->logicalTopVisualOverflow(root.lineTop()), curr->logicalBottomVisualOverflow(root.lineBottom()), cullRect, accumulatedOffset)) { bool inside = curr->nodeAtPoint(result, locationInContainer, accumulatedOffset, root.lineTop(), root.lineBottom()); if (inside) { layoutObject.updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); return true; } } } return false; }