📄 renderlayer.cpp
字号:
// Schedule the scroll DOM event. if (view) { if (FrameView* frameView = view->frameView()) frameView->scheduleEvent(Event::create(eventNames().scrollEvent, false, false), renderer()->node()); }}void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, const ScrollAlignment& alignX, const ScrollAlignment& alignY){ RenderLayer* parentLayer = 0; IntRect newRect = rect; int xOffset = 0, yOffset = 0; // We may end up propagating a scroll event. It is important that we suspend events until // the end of the function since they could delete the layer or the layer's renderer(). FrameView* frameView = renderer()->document()->view(); if (frameView) frameView->pauseScheduledEvents(); bool restrictedByLineClamp = false; if (renderer()->parent()) { parentLayer = renderer()->parent()->enclosingLayer(); restrictedByLineClamp = renderer()->parent()->style()->lineClamp() >= 0; } if (renderer()->hasOverflowClip() && !restrictedByLineClamp) { // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property. // This will prevent us from revealing text hidden by the slider in Safari RSS. RenderBox* box = renderBox(); ASSERT(box); FloatPoint absPos = box->localToAbsolute(); absPos.move(box->borderLeft(), box->borderTop()); IntRect layerBounds = IntRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), box->clientWidth(), box->clientHeight()); IntRect exposeRect = IntRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height()); IntRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY); xOffset = r.x() - absPos.x(); yOffset = r.y() - absPos.y(); // Adjust offsets if they're outside of the allowable range. xOffset = max(0, min(scrollWidth() - layerBounds.width(), xOffset)); yOffset = max(0, min(scrollHeight() - layerBounds.height(), yOffset)); if (xOffset != scrollXOffset() || yOffset != scrollYOffset()) { int diffX = scrollXOffset(); int diffY = scrollYOffset(); scrollToOffset(xOffset, yOffset); diffX = scrollXOffset() - diffX; diffY = scrollYOffset() - diffY; newRect.setX(rect.x() - diffX); newRect.setY(rect.y() - diffY); } } else if (!parentLayer && renderer()->isBox() && renderBox()->canBeProgramaticallyScrolled(scrollToAnchor)) { if (frameView) { if (renderer()->document() && renderer()->document()->ownerElement() && renderer()->document()->ownerElement()->renderer()) { IntRect viewRect = frameView->visibleContentRect(); IntRect r = getRectToExpose(viewRect, rect, alignX, alignY); xOffset = r.x(); yOffset = r.y(); // Adjust offsets if they're outside of the allowable range. xOffset = max(0, min(frameView->contentsWidth(), xOffset)); yOffset = max(0, min(frameView->contentsHeight(), yOffset)); frameView->setScrollPosition(IntPoint(xOffset, yOffset)); parentLayer = renderer()->document()->ownerElement()->renderer()->enclosingLayer(); newRect.setX(rect.x() - frameView->scrollX() + frameView->x()); newRect.setY(rect.y() - frameView->scrollY() + frameView->y()); } else { IntRect viewRect = frameView->visibleContentRect(true); IntRect r = getRectToExpose(viewRect, rect, alignX, alignY); // If this is the outermost view that RenderLayer needs to scroll, then we should scroll the view recursively // Other apps, like Mail, rely on this feature. frameView->scrollRectIntoViewRecursively(r); } } } if (parentLayer) parentLayer->scrollRectToVisible(newRect, scrollToAnchor, alignX, alignY); if (frameView) frameView->resumeScheduledEvents();}IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY){ // Determine the appropriate X behavior. ScrollBehavior scrollX; IntRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height()); int intersectWidth = intersection(visibleRect, exposeRectX).width(); if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL) // If the rectangle is fully visible, use the specified visible behavior. // If the rectangle is partially visible, but over a certain threshold, // then treat it as fully visible to avoid unnecessary horizontal scrolling scrollX = ScrollAlignment::getVisibleBehavior(alignX); else if (intersectWidth == visibleRect.width()) { // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work. scrollX = ScrollAlignment::getVisibleBehavior(alignX); if (scrollX == alignCenter) scrollX = noScroll; } else if (intersectWidth > 0) // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior scrollX = ScrollAlignment::getPartialBehavior(alignX); else scrollX = ScrollAlignment::getHiddenBehavior(alignX); // If we're trying to align to the closest edge, and the exposeRect is further right // than the visibleRect, and not bigger than the visible area, then align with the right. if (scrollX == alignToClosestEdge && exposeRect.right() > visibleRect.right() && exposeRect.width() < visibleRect.width()) scrollX = alignRight; // Given the X behavior, compute the X coordinate. int x; if (scrollX == noScroll) x = visibleRect.x(); else if (scrollX == alignRight) x = exposeRect.right() - visibleRect.width(); else if (scrollX == alignCenter) x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2; else x = exposeRect.x(); // Determine the appropriate Y behavior. ScrollBehavior scrollY; IntRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height()); int intersectHeight = intersection(visibleRect, exposeRectY).height(); if (intersectHeight == exposeRect.height()) // If the rectangle is fully visible, use the specified visible behavior. scrollY = ScrollAlignment::getVisibleBehavior(alignY); else if (intersectHeight == visibleRect.height()) { // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work. scrollY = ScrollAlignment::getVisibleBehavior(alignY); if (scrollY == alignCenter) scrollY = noScroll; } else if (intersectHeight > 0) // If the rectangle is partially visible, use the specified partial behavior scrollY = ScrollAlignment::getPartialBehavior(alignY); else scrollY = ScrollAlignment::getHiddenBehavior(alignY); // If we're trying to align to the closest edge, and the exposeRect is further down // than the visibleRect, and not bigger than the visible area, then align with the bottom. if (scrollY == alignToClosestEdge && exposeRect.bottom() > visibleRect.bottom() && exposeRect.height() < visibleRect.height()) scrollY = alignBottom; // Given the Y behavior, compute the Y coordinate. int y; if (scrollY == noScroll) y = visibleRect.y(); else if (scrollY == alignBottom) y = exposeRect.bottom() - visibleRect.height(); else if (scrollY == alignCenter) y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2; else y = exposeRect.y(); return IntRect(IntPoint(x, y), visibleRect.size());}void RenderLayer::autoscroll(){ Frame* frame = renderer()->document()->frame(); if (!frame) return; FrameView* frameView = frame->view(); if (!frameView) return; frame->eventHandler()->updateSelectionForMouseDrag(); IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition()); scrollRectToVisible(IntRect(currentDocumentPosition, IntSize(1, 1)), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);}void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset){ // FIXME: This should be possible on generated content but is not right now. if (!inResizeMode() || !renderer()->hasOverflowClip() || !renderer()->node()) return; // Set the width and height of the shadow ancestor node if there is one. // This is necessary for textarea elements since the resizable layer is in the shadow content. Element* element = static_cast<Element*>(renderer()->node()->shadowAncestorNode()); RenderBox* renderer = toRenderBox(element->renderer()); EResize resize = renderer->style()->resize(); if (resize == RESIZE_NONE) return; Document* document = element->document(); if (!document->frame()->eventHandler()->mousePressed()) return; float zoomFactor = renderer->style()->effectiveZoom(); IntSize newOffset = offsetFromResizeCorner(document->view()->windowToContents(evt.pos())); newOffset.setWidth(newOffset.width() / zoomFactor); newOffset.setHeight(newOffset.height() / zoomFactor); IntSize currentSize = IntSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor); IntSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize); element->setMinimumSizeForResizing(minimumSize); IntSize adjustedOldOffset = IntSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor); IntSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize; CSSStyleDeclaration* style = element->style(); bool isBoxSizingBorder = renderer->style()->boxSizing() == BORDER_BOX; ExceptionCode ec; if (difference.width()) { if (element && element->isFormControlElement()) { // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>). style->setProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false, ec); style->setProperty(CSSPropertyMarginRight, String::number(renderer->marginRight() / zoomFactor) + "px", false, ec); } int baseWidth = renderer->width() - (isBoxSizingBorder ? 0 : renderer->borderLeft() + renderer->paddingLeft() + renderer->borderRight() + renderer->paddingRight()); baseWidth = baseWidth / zoomFactor; style->setProperty(CSSPropertyWidth, String::number(baseWidth + difference.width()) + "px", false, ec); } if (difference.height()) { if (element && element->isFormControlElement()) { // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>). style->setProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false, ec); style->setProperty(CSSPropertyMarginBottom, String::number(renderer->marginBottom() / zoomFactor) + "px", false, ec); } int baseHeight = renderer->height() - (isBoxSizingBorder ? 0 : renderer->borderTop() + renderer->paddingTop() + renderer->borderBottom() + renderer->paddingBottom()); baseHeight = baseHeight / zoomFactor; style->setProperty(CSSPropertyHeight, String::number(baseHeight + difference.height()) + "px", false, ec); } document->updateLayout(); // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.}void RenderLayer::valueChanged(Scrollbar*){ // Update scroll position from scrollbars. bool needUpdate = false; int newX = scrollXOffset(); int newY = m_scrollY; if (m_hBar) { newX = m_hBar->value(); if (newX != scrollXOffset()) needUpdate = true; } if (m_vBar) { newY = m_vBar->value(); if (newY != m_scrollY) needUpdate = true; } if (needUpdate) scrollToOffset(newX, newY, false);}bool RenderLayer::isActive() const{ Page* page = renderer()->document()->frame()->page(); return page && page->focusController()->isActive();}static IntRect cornerRect(const RenderLayer* layer, const IntRect& bounds){ int horizontalThickness; int verticalThickness; if (!layer->verticalScrollbar() && !layer->horizontalScrollbar()) { // FIXME: This isn't right. We need to know the thickness of custom scrollbars // even when they don't exist in order to set the resizer square size properly. horizontalThickness = ScrollbarTheme::nativeTheme()->scrollbarThickness(); verticalThickness = horizontalThickness; } else if (layer->verticalScrollbar() && !layer->horizontalScrollbar()) { horizontalThickness = layer->verticalScrollbar()->width(); verticalThickness = horizontalThickness; } else if (layer->horizontalScrollbar() && !layer->verticalScrollbar()) { verticalThickness = layer->horizontalScrollbar()->height(); horizontalThickness = verticalThickness; } else { horizontalThickness = layer->verticalScrollbar()->width(); verticalThickness = layer->horizontalScrollbar()->height(); } return IntRect(bounds.right() - horizontalThickness - layer->renderer()->style()->borderRightWidth(), bounds.bottom() - verticalThickness - layer->renderer()->style()->borderBottomWidth(), horizontalThickness, verticalThickness);}static IntRect scrollCornerRect(const RenderLayer* layer, const IntRect& bounds){ // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box. // This happens when: // (a) A resizer is present and at least one scrollbar is present // (b) Both scrollbars are present. bool hasHorizontalBar = layer->horizontalScrollbar(); bool hasVerticalBar = layer->verticalScrollbar(); bool hasResizer = layer->renderer()->style()->resize() != RESIZE_NONE; if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar))) return cornerRect(layer, bounds); return IntRect();}static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds){ ASSERT(layer->renderer()->isBox()); if (layer->renderer()->style()->resize() == RESIZE_NONE) return IntRect(); return cornerRect(layer, bounds);}bool RenderLayer::scrollbarCornerPresent() const{ ASSERT(renderer()->isBox()); return !scrollCornerRect(this, renderBox()->borderBoxRect()).isEmpty();}void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect){ IntRect scrollRect = rect; RenderBox* box = renderBox(); ASSERT(box); if (scrollbar == m_vBar.get()) scrollRect.move(box->width() - box->borderRight() - box->width(), box->borderTop()); else scrollRect.move(box->borderLeft(), box->height() - box->borderBottom() - scrollbar->height()); renderer()->repaintRectangle(scrollRect);}PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation){ RefPtr<Scrollbar> widget; RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer(); bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR); if (hasCustomScrollbarStyle) widget = RenderScrollbar::createCustomScrollbar(this, orientation, toRenderBox(actualRenderer)); else widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar); renderer()->document()->view()->addChild(widget.get()); return widget.release();}void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation){ RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar; if (scrollbar) { scrollbar->removeFromParent(); scrollbar->setClient(0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -