SimpleLineLayoutFunctions.cpp [plain text]
#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 "RenderStyle.h"
#include "RenderText.h"
#include "RenderView.h"
#include "Settings.h"
#include "SimpleLineLayoutResolver.h"
#include "Text.h"
#include "TextPaintStyle.h"
namespace WebCore {
namespace SimpleLineLayout {
static void paintDebugBorders(GraphicsContext& context, LayoutRect borderRect, const LayoutPoint& paintOffset)
{
borderRect.moveBy(paintOffset);
IntRect snappedRect = pixelSnappedIntRect(borderRect);
if (snappedRect.isEmpty())
return;
GraphicsContextStateSaver stateSaver(context);
context.setStrokeColor(Color(0, 255, 0), ColorSpaceDeviceRGB);
context.setFillColor(Color::transparent, ColorSpaceDeviceRGB);
context.drawRect(snappedRect);
}
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;
RenderText& textRenderer = toRenderText(*flow.firstChild());
ASSERT(!textRenderer.firstTextBox());
bool debugBordersEnabled = flow.frame().settings().simpleLineLayoutDebugBordersEnabled();
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 = LayoutPoint(roundedForPainting(paintOffset, flow.document().deviceScaleFactor()));
LayoutRect paintRect = paintInfo.rect;
paintRect.moveBy(-adjustedPaintOffset);
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))
continue;
TextRun textRun(run.text());
textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
context.drawText(font, textRun, run.baseline() + adjustedPaintOffset);
if (debugBordersEnabled)
paintDebugBorders(context, run.rect(), adjustedPaintOffset);
}
}
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;
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);
if (!locationInContainer.intersects(lineRect))
continue;
textRenderer.updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset));
if (!result.addNodeToRectBasedTestResult(textRenderer.textNode(), 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);
}
}
IntRect computeTextBoundingBox(const RenderText& textRenderer, 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();
}
float x = left;
float y = firstLineRect.y();
float width = right - left;
float height = bottom - y;
return enclosingIntRect(FloatRect(x, y, width, height));
}
IntPoint computeTextFirstRunLocation(const RenderText& textRenderer, const Layout& layout)
{
auto resolver = runResolver(toRenderBlockFlow(*textRenderer.parent()), layout);
auto begin = resolver.begin();
if (begin == resolver.end())
return IntPoint();
return flooredIntPoint((*begin).rect().location());
}
Vector<IntRect> collectTextAbsoluteRects(const RenderText& textRenderer, 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();
rects.append(enclosingIntRect(FloatRect(accumulatedOffset + rect.location(), rect.size())));
}
return rects;
}
Vector<FloatQuad> collectTextAbsoluteQuads(const RenderText& textRenderer, const Layout& layout, bool* wasFixed)
{
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));
}
return quads;
}
}
}