diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
download | qtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp')
-rw-r--r-- | Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp b/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp new file mode 100644 index 000000000..ff04fbb15 --- /dev/null +++ b/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SimpleLineLayoutFunctions.h" + +#include "FontCache.h" +#include "Frame.h" +#include "GraphicsContext.h" +#include "HitTestLocation.h" +#include "HitTestRequest.h" +#include "HitTestResult.h" +#include "InlineTextBox.h" +#include "PaintInfo.h" +#include "RenderBlockFlow.h" +#include "RenderIterator.h" +#include "RenderStyle.h" +#include "RenderText.h" +#include "RenderView.h" +#include "Settings.h" +#include "SimpleLineLayoutResolver.h" +#include "Text.h" +#include "TextDecorationPainter.h" +#include "TextPaintStyle.h" +#include "TextPainter.h" + +#if ENABLE(TREE_DEBUGGING) +#include <stdio.h> +#endif + +namespace WebCore { +namespace SimpleLineLayout { + +static void paintDebugBorders(GraphicsContext& context, LayoutRect borderRect, const LayoutPoint& paintOffset) +{ + borderRect.moveBy(paintOffset); + IntRect snappedRect = snappedIntRect(borderRect); + if (snappedRect.isEmpty()) + return; + GraphicsContextStateSaver stateSaver(context); + context.setStrokeColor(Color(0, 255, 0)); + context.setFillColor(Color::transparent); + context.drawRect(snappedRect); +} + +static FloatRect computeOverflow(const RenderBlockFlow& flow, const FloatRect& layoutRect) +{ + auto overflowRect = layoutRect; + auto strokeOverflow = std::ceil(flow.style().textStrokeWidth()); + overflowRect.inflate(strokeOverflow); + + auto letterSpacing = flow.style().fontCascade().letterSpacing(); + if (letterSpacing >= 0) + return overflowRect; + // Last letter's negative spacing shrinks layout rect. Push it to visual overflow. + overflowRect.expand(-letterSpacing, 0); + return overflowRect; +} + +void paintFlow(const RenderBlockFlow& flow, const Layout& layout, PaintInfo& paintInfo, const LayoutPoint& paintOffset) +{ + if (paintInfo.phase != PaintPhaseForeground) + return; + + RenderStyle& style = flow.style(); + if (style.visibility() != VISIBLE) + return; + + bool debugBordersEnabled = flow.frame().settings().simpleLineLayoutDebugBordersEnabled(); + + TextPainter textPainter(paintInfo.context()); + textPainter.setFont(style.fontCascade()); + textPainter.setTextPaintStyle(computeTextPaintStyle(flow.frame(), style, paintInfo)); + + Optional<TextDecorationPainter> textDecorationPainter; + if (style.textDecorationsInEffect() != TextDecorationNone) { + const RenderText* textRenderer = childrenOfType<RenderText>(flow).first(); + if (textRenderer) { + textDecorationPainter = TextDecorationPainter(paintInfo.context(), style.textDecorationsInEffect(), *textRenderer, false); + textDecorationPainter->setFont(style.fontCascade()); + textDecorationPainter->setBaseline(style.fontMetrics().ascent()); + } + } + + LayoutRect paintRect = paintInfo.rect; + paintRect.moveBy(-paintOffset); + + auto resolver = runResolver(flow, layout); + float deviceScaleFactor = flow.document().deviceScaleFactor(); + for (auto run : resolver.rangeForRect(paintRect)) { + if (run.start() == run.end()) + continue; + + FloatRect rect = run.rect(); + FloatRect visualOverflowRect = computeOverflow(flow, rect); + if (paintRect.y() > visualOverflowRect.maxY() || paintRect.maxY() < visualOverflowRect.y()) + continue; + + TextRun textRun(run.text()); + textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize()); + // x position indicates the line offset from the rootbox. It's always 0 in case of simple line layout. + textRun.setXPos(0); + FloatPoint textOrigin = FloatPoint(rect.x() + paintOffset.x(), roundToDevicePixel(run.baselinePosition() + paintOffset.y(), deviceScaleFactor)); + textPainter.paintText(textRun, textRun.length(), rect, textOrigin); + if (textDecorationPainter) { + textDecorationPainter->setWidth(rect.width()); + textDecorationPainter->paintTextDecoration(textRun, textOrigin, rect.location() + paintOffset); + } + if (debugBordersEnabled) + paintDebugBorders(paintInfo.context(), LayoutRect(run.rect()), paintOffset); + } +} + +bool hitTestFlow(const RenderBlockFlow& flow, const Layout& layout, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) +{ + if (hitTestAction != HitTestForeground) + return false; + + if (!layout.runCount()) + return false; + + RenderStyle& style = flow.style(); + if (style.visibility() != VISIBLE || style.pointerEvents() == PE_NONE) + return false; + + RenderObject& renderer = *flow.firstChild(); + LayoutRect rangeRect = locationInContainer.boundingBox(); + rangeRect.moveBy(-accumulatedOffset); + + auto resolver = lineResolver(flow, layout); + for (FloatRect lineRect : resolver.rangeForRect(rangeRect)) { + lineRect.moveBy(accumulatedOffset); + if (!locationInContainer.intersects(lineRect)) + continue; + renderer.updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); + if (!result.addNodeToRectBasedTestResult(renderer.node(), request, locationInContainer, lineRect)) + return true; + } + + return false; +} + +void collectFlowOverflow(RenderBlockFlow& flow, const Layout& layout) +{ + for (auto lineRect : lineResolver(flow, layout)) { + LayoutRect visualOverflowRect = LayoutRect(computeOverflow(flow, lineRect)); + flow.addLayoutOverflow(LayoutRect(lineRect)); + flow.addVisualOverflow(visualOverflowRect); + } +} + +IntRect computeBoundingBox(const RenderObject& renderer, const Layout& layout) +{ + auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout); + FloatRect boundingBoxRect; + for (auto run : resolver.rangeForRenderer(renderer)) { + FloatRect rect = run.rect(); + if (boundingBoxRect == FloatRect()) + boundingBoxRect = rect; + else + boundingBoxRect.uniteEvenIfEmpty(rect); + } + return enclosingIntRect(boundingBoxRect); +} + +IntPoint computeFirstRunLocation(const RenderObject& renderer, const Layout& layout) +{ + auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout); + auto range = resolver.rangeForRenderer(renderer); + auto begin = range.begin(); + if (begin == range.end()) + return IntPoint(0, 0); + return flooredIntPoint((*begin).rect().location()); +} + +Vector<IntRect> collectAbsoluteRects(const RenderObject& renderer, const Layout& layout, const LayoutPoint& accumulatedOffset) +{ + Vector<IntRect> rects; + auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout); + for (auto run : resolver.rangeForRenderer(renderer)) { + FloatRect rect = run.rect(); + rects.append(enclosingIntRect(FloatRect(accumulatedOffset + rect.location(), rect.size()))); + } + return rects; +} + +Vector<FloatQuad> collectAbsoluteQuads(const RenderObject& renderer, const Layout& layout, bool* wasFixed) +{ + Vector<FloatQuad> quads; + auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout); + for (auto run : resolver.rangeForRenderer(renderer)) + quads.append(renderer.localToAbsoluteQuad(FloatQuad(run.rect()), UseTransforms, wasFixed)); + return quads; +} + +#if ENABLE(TREE_DEBUGGING) +static void printPrefix(int& printedCharacters, int depth) +{ + fprintf(stderr, "------- --"); + printedCharacters = 0; + while (++printedCharacters <= depth * 2) + fputc(' ', stderr); +} + +void showLineLayoutForFlow(const RenderBlockFlow& flow, const Layout& layout, int depth) +{ + int printedCharacters = 0; + printPrefix(printedCharacters, depth); + + fprintf(stderr, "SimpleLineLayout (%u lines, %u runs) (%p)\n", layout.lineCount(), layout.runCount(), &layout); + ++depth; + + for (auto run : runResolver(flow, layout)) { + FloatRect rect = run.rect(); + printPrefix(printedCharacters, depth); + if (run.start() < run.end()) { + fprintf(stderr, "line %u run(%u, %u) (%.2f, %.2f) (%.2f, %.2f) \"%s\"\n", run.lineIndex(), run.start(), run.end(), + rect.x(), rect.y(), rect.width(), rect.height(), run.text().toStringWithoutCopying().utf8().data()); + } else { + ASSERT(run.start() == run.end()); + fprintf(stderr, "line break %u run(%u, %u) (%.2f, %.2f) (%.2f, %.2f)\n", run.lineIndex(), run.start(), run.end(), rect.x(), rect.y(), rect.width(), rect.height()); + } + } +} +#endif + +} +} |