diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp')
-rw-r--r-- | Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp | 250 |
1 files changed, 176 insertions, 74 deletions
diff --git a/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp b/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp index 346879569..12a903647 100644 --- a/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp +++ b/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp @@ -35,28 +35,48 @@ #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 <wtf/unicode/Unicode.h> +#include "TextPainter.h" + +#if ENABLE(TREE_DEBUGGING) +#include <stdio.h> +#endif namespace WebCore { namespace SimpleLineLayout { -static void paintDebugBorders(GraphicsContext& context, const LayoutRect& borderRect, const LayoutPoint& paintOffset) +static void paintDebugBorders(GraphicsContext& context, LayoutRect borderRect, const LayoutPoint& paintOffset) { - if (borderRect.isEmpty()) + borderRect.moveBy(paintOffset); + IntRect snappedRect = snappedIntRect(borderRect); + if (snappedRect.isEmpty()) return; GraphicsContextStateSaver stateSaver(context); - context.setStrokeColor(Color(0, 255, 0), ColorSpaceDeviceRGB); - context.setFillColor(Color::transparent, ColorSpaceDeviceRGB); - LayoutRect rect(borderRect); - rect.moveBy(paintOffset); - context.drawRect(pixelSnappedIntRect(rect)); + 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) @@ -64,38 +84,54 @@ void paintFlow(const RenderBlockFlow& flow, const Layout& layout, PaintInfo& pai if (paintInfo.phase != PaintPhaseForeground) return; - RenderStyle& style = flow.style(); + auto& style = flow.style(); if (style.visibility() != VISIBLE) return; - RenderText& textRenderer = toRenderText(*flow.firstChild()); - ASSERT(!textRenderer.firstTextBox()); + bool debugBordersEnabled = flow.settings().simpleLineLayoutDebugBordersEnabled(); - bool debugBordersEnabled = flow.frame().settings().simpleLineLayoutDebugBordersEnabled(); + TextPainter textPainter(paintInfo.context()); + textPainter.setFont(style.fontCascade()); + textPainter.setTextPaintStyle(computeTextPaintStyle(flow.frame(), style, paintInfo)); - GraphicsContext& context = *paintInfo.context; - - const Font& font = style.font(); - TextPaintStyle textPaintStyle = computeTextPaintStyle(textRenderer, style, paintInfo); - GraphicsContextStateSaver stateSaver(context, textPaintStyle.strokeWidth > 0); - - updateGraphicsContext(context, textPaintStyle); - LayoutPoint adjustedPaintOffset = roundedIntPoint(paintOffset); + std::optional<TextDecorationPainter> textDecorationPainter; + if (style.textDecorationsInEffect() != TextDecorationNone) { + const RenderText* textRenderer = childrenOfType<RenderText>(flow).first(); + if (textRenderer) { + textDecorationPainter.emplace(paintInfo.context(), style.textDecorationsInEffect(), *textRenderer, false); + textDecorationPainter->setFont(style.fontCascade()); + textDecorationPainter->setBaseline(style.fontMetrics().ascent()); + } + } LayoutRect paintRect = paintInfo.rect; - paintRect.moveBy(-adjustedPaintOffset); + paintRect.moveBy(-paintOffset); auto resolver = runResolver(flow, layout); - auto range = resolver.rangeForRect(paintRect); - for (auto it = range.begin(), end = range.end(); it != end; ++it) { - const auto& run = *it; - if (!run.rect().intersects(paintRect)) + 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()); + + String textWithHyphen; + if (run.hasHyphen()) + textWithHyphen = run.textWithHyphen(); + // x position indicates the line offset from the rootbox. It's always 0 in case of simple line layout. + TextRun textRun(run.hasHyphen() ? textWithHyphen : run.text(), 0, run.expansion(), run.expansionBehavior()); textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize()); - context.drawText(font, textRun, run.baseline() + adjustedPaintOffset); + 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(context, run.rect(), adjustedPaintOffset); + paintDebugBorders(paintInfo.context(), LayoutRect(run.rect()), paintOffset); } } @@ -107,90 +143,156 @@ bool hitTestFlow(const RenderBlockFlow& flow, const Layout& layout, const HitTes if (!layout.runCount()) return false; - RenderStyle& style = flow.style(); + auto& style = flow.style(); if (style.visibility() != VISIBLE || style.pointerEvents() == PE_NONE) return false; - RenderText& textRenderer = toRenderText(*flow.firstChild()); - LayoutRect rangeRect = locationInContainer.boundingBox(); rangeRect.moveBy(-accumulatedOffset); - auto resolver = lineResolver(flow, layout); auto range = resolver.rangeForRect(rangeRect); for (auto it = range.begin(), end = range.end(); it != end; ++it) { auto lineRect = *it; lineRect.moveBy(accumulatedOffset); + auto& renderer = const_cast<RenderObject&>(it.renderer()); if (!locationInContainer.intersects(lineRect)) continue; - textRenderer.updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); - if (!result.addNodeToRectBasedTestResult(textRenderer.textNode(), request, locationInContainer, lineRect)) + 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) { - auto resolver = lineResolver(flow, layout); - for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) { - auto rect = *it; - flow.addLayoutOverflow(rect); - flow.addVisualOverflow(rect); + for (auto lineRect : lineResolver(flow, layout)) { + LayoutRect visualOverflowRect = LayoutRect(computeOverflow(flow, lineRect)); + flow.addLayoutOverflow(LayoutRect(lineRect)); + flow.addVisualOverflow(visualOverflowRect); } } -IntRect computeTextBoundingBox(const RenderText& textRenderer, const Layout& layout) +IntRect computeBoundingBox(const RenderObject& renderer, const Layout& layout) { - auto resolver = lineResolver(toRenderBlockFlow(*textRenderer.parent()), layout); - auto it = resolver.begin(); - auto end = resolver.end(); - if (it == end) - return IntRect(); - auto firstLineRect = *it; - float left = firstLineRect.x(); - float right = firstLineRect.maxX(); - float bottom = firstLineRect.maxY(); - for (++it; it != end; ++it) { - auto rect = *it; - if (rect.x() < left) - left = rect.x(); - if (rect.maxX() > right) - right = rect.maxX(); - if (rect.maxY() > bottom) - bottom = rect.maxY(); + 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); } - float x = firstLineRect.x(); - float y = firstLineRect.y(); - float width = right - left; - float height = bottom - y; - return enclosingIntRect(FloatRect(x, y, width, height)); + return enclosingIntRect(boundingBoxRect); } -Vector<IntRect> collectTextAbsoluteRects(const RenderText& textRenderer, const Layout& layout, const LayoutPoint& accumulatedOffset) +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(toRenderBlockFlow(*textRenderer.parent()), layout); - for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) { - const auto& run = *it; - auto rect = run.rect(); + 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> collectTextAbsoluteQuads(const RenderText& textRenderer, const Layout& layout, bool* wasFixed) +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; +} + +unsigned textOffsetForPoint(const LayoutPoint& point, const RenderText& renderer, const Layout& layout) +{ + auto& flow = downcast<RenderBlockFlow>(*renderer.parent()); + ASSERT(flow.firstChild() == flow.lastChild()); + auto resolver = runResolver(flow, layout); + auto it = resolver.runForPoint(point); + if (it == resolver.end()) + return renderer.textLength(); + auto run = *it; + auto& style = flow.style(); + TextRun textRun(run.text(), run.logicalLeft(), run.expansion(), run.expansionBehavior()); + textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize()); + return run.start() + style.fontCascade().offsetForPosition(textRun, point.x() - run.logicalLeft(), true); +} + +Vector<FloatQuad> collectAbsoluteQuadsForRange(const RenderObject& renderer, unsigned start, unsigned end, const Layout& layout, bool* wasFixed) { + auto& style = downcast<RenderBlockFlow>(*renderer.parent()).style(); Vector<FloatQuad> quads; - auto resolver = runResolver(toRenderBlockFlow(*textRenderer.parent()), layout); - for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) { - const auto& run = *it; - auto rect = run.rect(); - quads.append(textRenderer.localToAbsoluteQuad(FloatQuad(rect), 0, wasFixed)); + auto resolver = runResolver(downcast<RenderBlockFlow>(*renderer.parent()), layout); + for (auto run : resolver.rangeForRendererWithOffsets(renderer, start, end)) { + // This run is fully contained. + if (start <= run.start() && end >= run.end()) { + quads.append(renderer.localToAbsoluteQuad(FloatQuad(run.rect()), UseTransforms, wasFixed)); + continue; + } + // Partially contained run. + TextRun textRun(run.text(), run.logicalLeft(), run.expansion(), run.expansionBehavior()); + textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize()); + LayoutRect runRect(run.rect()); + // Special case empty ranges. + if (start == end) { + runRect.setWidth(0); + quads.append(renderer.localToAbsoluteQuad(FloatQuad(runRect), UseTransforms, wasFixed)); + continue; + } + ASSERT(start < run.end()); + ASSERT(end > run.start()); + auto localStart = std::max(run.start(), start) - run.start(); + auto localEnd = std::min(run.end(), end) - run.start(); + style.fontCascade().adjustSelectionRectForText(textRun, runRect, localStart, localEnd); + quads.append(renderer.localToAbsoluteQuad(FloatQuad(runRect), 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 + } } |