KHtml

RenderPath.cpp
1 /*
2  Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <[email protected]>
3  2004, 2005 Rob Buis <[email protected]>
4  2005, 2007 Eric Seidel <[email protected]>
5 
6  This file is part of the KDE project
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public
10  License as published by the Free Software Foundation; either
11  version 2 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Library General Public License for more details.
17 
18  You should have received a copy of the GNU Library General Public License
19  aint with this library; see the file COPYING.LIB. If not, write to
20  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  Boston, MA 02110-1301, USA.
22 */
23 
24 #include "wtf/Platform.h"
25 #include "Document.h"
26 
27 #if ENABLE(SVG)
28 #include "RenderPath.h"
29 
30 #include <math.h>
31 
32 /*#include "GraphicsContext.h"
33 #include "PointerEventsHitRules.h"*/
34 #include "RenderSVGContainer.h"
35 #include "SVGPaintServer.h"
36 #include "SVGRenderSupport.h"
37 /*#include "SVGResourceFilter.h"
38 #include "SVGResourceMarker.h"
39 #include "SVGResourceMasker.h"*/
40 #include "SVGStyledTransformableElement.h"
41 #include "SVGTransformList.h"
42 #include "SVGURIReference.h"
43 
44 #include <wtf/MathExtras.h>
45 
46 namespace WebCore
47 {
48 
49 // RenderPath
50 RenderPath::RenderPath(RenderStyle *style, SVGStyledTransformableElement *node)
51  : RenderObject(node)
52 {
53  ASSERT(style != nullptr); Q_UNUSED(style);
54  ASSERT(static_cast<SVGElement *>(node)->isStyledTransformable());
55 }
56 
57 RenderPath::~RenderPath()
58 {
59 }
60 
61 AffineTransform RenderPath::localTransform() const
62 {
63  return m_localTransform;
64 }
65 
66 FloatPoint RenderPath::mapAbsolutePointToLocal(const FloatPoint &point) const
67 {
68  // FIXME: does it make sense to map incoming points with the inverse of the
69  // absolute transform?
70  double localX;
71  double localY;
72  absoluteTransform().inverse().map(point.x(), point.y(), &localX, &localY);
73  return FloatPoint::narrowPrecision(localX, localY);
74 }
75 
76 bool RenderPath::fillContains(const FloatPoint &point, bool requiresFill) const
77 {
78  if (m_path.isEmpty()) {
79  return false;
80  }
81 
82  if (requiresFill && !SVGPaintServer::fillPaintServer(style(), this)) {
83  return false;
84  }
85 
86  return m_path.contains(point, style()->svgStyle()->fillRule());
87 }
88 
89 FloatRect RenderPath::relativeBBox(bool includeStroke) const
90 {
91  if (m_path.isEmpty()) {
92  return FloatRect();
93  }
94 
95  if (includeStroke) {
96  if (m_strokeBbox.isEmpty())
97  /*m_strokeBbox = strokeBBox();*/
98 
99  {
100  return m_strokeBbox;
101  }
102  }
103 
104  if (m_fillBBox.isEmpty()) {
105  m_fillBBox = m_path.boundingRect();
106  }
107 
108  return m_fillBBox;
109 }
110 
111 void RenderPath::setPath(const Path &newPath)
112 {
113  m_path = newPath;
114  m_strokeBbox = FloatRect();
115  m_fillBBox = FloatRect();
116 }
117 
118 const Path &RenderPath::path() const
119 {
120  return m_path;
121 }
122 
123 bool RenderPath::calculateLocalTransform()
124 {
125  AffineTransform oldTransform = m_localTransform;
126  m_localTransform = static_cast<SVGStyledTransformableElement *>(element())->animatedLocalTransform();
127  return (m_localTransform != oldTransform);
128 }
129 
130 void RenderPath::layout()
131 {
132  IntRect oldBounds;
133  IntRect oldOutlineBox;
134  bool checkForRepaint = /*checkForRepaintDuringLayout() && */selfNeedsLayout();
135  if (checkForRepaint) {
136  oldBounds = m_absoluteBounds;
137  //oldOutlineBox = absoluteOutlineBox();
138  }
139 
140  calculateLocalTransform();
141 
142  setPath(static_cast<SVGStyledTransformableElement *>(element())->toPathData());
143 
144  m_absoluteBounds = absoluteClippedOverflowRect();
145 
146  setWidth(m_absoluteBounds.width());
147  setHeight(m_absoluteBounds.height());
148 
149  /*if (checkForRepaint)
150  repaintAfterLayoutIfNeeded(oldBounds, oldOutlineBox);*/
151 
152  setNeedsLayout(false);
153 }
154 
155 IntRect RenderPath::absoluteClippedOverflowRect()
156 {
157  return IntRect(0, 0, 100, 100);
158  /*FloatRect repaintRect = absoluteTransform().mapRect(relativeBBox(true));
159 
160  // Markers can expand the bounding box
161  repaintRect.unite(m_markerBounds);
162 
163  #if ENABLE(SVG_FILTERS)
164  // Filters can expand the bounding box
165  SVGResourceFilter* filter = getFilterById(document(), SVGURIReference::getTarget(style()->svgStyle()->filter()));
166  if (filter)
167  repaintRect.unite(filter->filterBBoxForItemBBox(repaintRect));
168  #endif
169 
170  if (!repaintRect.isEmpty())
171  repaintRect.inflate(1); // inflate 1 pixel for antialiasing
172 
173  return enclosingIntRect(repaintRect);*/
174 }
175 
176 bool RenderPath::requiresLayer() const
177 {
178  return false;
179 }
180 
181 short RenderPath::lineHeight(bool b) const
182 {
183  Q_UNUSED(b);
184  return static_cast<short>(relativeBBox(true).height());
185 }
186 
187 short RenderPath::baselinePosition(bool b) const
188 {
189  Q_UNUSED(b);
190  return static_cast<short>(relativeBBox(true).height());
191 }
192 
193 static inline void fillAndStrokePath(const Path &path, QPainter *painter, RenderStyle *style, RenderPath *object)
194 {
195  /*context->beginPath();*/
196 
197  SVGPaintServer *fillPaintServer = SVGPaintServer::fillPaintServer(style, object);
198  if (fillPaintServer) {
199  /*context->addPath(path);*/
200  fillPaintServer->draw(painter, path.platformPath(), object, ApplyToFillTargetType);
201  }
202 
203  SVGPaintServer *strokePaintServer = SVGPaintServer::strokePaintServer(style, object);
204  if (strokePaintServer) {
205  /*context->addPath(path); // path is cleared when filled.*/
206  strokePaintServer->draw(painter, path.platformPath(), object, ApplyToStrokeTargetType);
207  }
208 }
209 
210 void RenderPath::paint(PaintInfo &paintInfo, int, int)
211 {
212  paintInfo.p->save();
213  paintInfo.p->setWorldMatrix(localTransform(), true);
214  SVGResourceFilter *filter = nullptr;
215  prepareToRenderSVGContent(this, paintInfo, FloatRect(), filter/*boundingBox, filter*/);
216  if (paintInfo.phase == PaintActionForeground) {
217  fillAndStrokePath(m_path, paintInfo.p, style(), this);
218  }
219  paintInfo.p->restore();
220 
221 #if 0
222  /*if (paintInfo.context->paintingDisabled() || style()->visibility() == HIDDEN || m_path.isEmpty())
223  return;*/
224 
225  //paintInfo.context->save();
226  /*paintInfo.context->concatCTM(localTransform());*/
227 
228  //paintInfo.p->fillRect(0, 0, 50, 50, QBrush(Qt::yellow));
229  /*paintInfo.p->setPen(Qt::blue);
230  // qCDebug(KHTML_LOG) << "path:" << *m_path.platformPath();
231  paintInfo.p->drawPath(*m_path.platformPath());*/
232  /*SVGResourceFilter* filter = 0;
233 
234  FloatRect boundingBox = relativeBBox(true);
235  if (paintInfo.phase == PaintPhaseForeground) {
236  PaintInfo savedInfo(paintInfo);
237 
238  prepareToRenderSVGContent(this, paintInfo, boundingBox, filter);
239  if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES)
240  paintInfo.context->setUseAntialiasing(false);
241  fillAndStrokePath(m_path, paintInfo.context, style(), this);
242 
243  if (static_cast<SVGStyledElement*>(element())->supportsMarkers())
244  m_markerBounds = drawMarkersIfNeeded(paintInfo.context, paintInfo.rect, m_path);
245 
246  finishRenderSVGContent(this, paintInfo, boundingBox, filter, savedInfo.context);
247  }
248 
249  if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style()->outlineWidth())
250  paintOutline(paintInfo.context, static_cast<int>(boundingBox.x()), static_cast<int>(boundingBox.y()),
251  static_cast<int>(boundingBox.width()), static_cast<int>(boundingBox.height()), style());*/
252 
253  //paintInfo.context->restore();
254 #endif
255 }
256 
257 /*void RenderPath::addFocusRingRects(GraphicsContext* graphicsContext, int, int)
258 {
259  graphicsContext->addFocusRingRect(enclosingIntRect(relativeBBox(true)));
260 }*/
261 
262 void RenderPath::absoluteRects(Vector<IntRect> &rects, int, int, bool)
263 {
264  rects.append(absoluteClippedOverflowRect());
265 }
266 
267 /*bool RenderPath::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int, int, HitTestAction hitTestAction)
268 {
269  // We only draw in the forground phase, so we only hit-test then.
270  if (hitTestAction != HitTestForeground)
271  return false;
272 
273  IntPoint absolutePoint(_x, _y);
274 
275  PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_PATH_HITTESTING, style()->svgStyle()->pointerEvents());
276 
277  bool isVisible = (style()->visibility() == VISIBLE);
278  if (isVisible || !hitRules.requireVisible) {
279  FloatPoint hitPoint = mapAbsolutePointToLocal(absolutePoint);
280  if ((hitRules.canHitStroke && (style()->svgStyle()->hasStroke() || !hitRules.requireStroke) && strokeContains(hitPoint, hitRules.requireStroke))
281  || (hitRules.canHitFill && (style()->svgStyle()->hasFill() || !hitRules.requireFill) && fillContains(hitPoint, hitRules.requireFill))) {
282  updateHitTestResult(result, absolutePoint);
283  return true;
284  }
285  }
286 
287  return false;
288 }*/
289 
290 /*enum MarkerType {
291  Start,
292  Mid,
293  End
294 };
295 
296 struct MarkerData {
297  FloatPoint origin;
298  FloatPoint subpathStart;
299  double strokeWidth;
300  FloatPoint inslopePoints[2];
301  FloatPoint outslopePoints[2];
302  MarkerType type;
303  SVGResourceMarker* marker;
304 };
305 
306 struct DrawMarkersData {
307  DrawMarkersData(GraphicsContext*, SVGResourceMarker* startMarker, SVGResourceMarker* midMarker, double strokeWidth);
308  GraphicsContext* context;
309  int elementIndex;
310  MarkerData previousMarkerData;
311  SVGResourceMarker* midMarker;
312 };
313 
314 DrawMarkersData::DrawMarkersData(GraphicsContext* c, SVGResourceMarker *start, SVGResourceMarker *mid, double strokeWidth)
315  : context(c)
316  , elementIndex(0)
317  , midMarker(mid)
318 {
319  previousMarkerData.origin = FloatPoint();
320  previousMarkerData.subpathStart = FloatPoint();
321  previousMarkerData.strokeWidth = strokeWidth;
322  previousMarkerData.marker = start;
323  previousMarkerData.type = Start;
324 }
325 
326 static void drawMarkerWithData(GraphicsContext* context, MarkerData &data)
327 {
328  if (!data.marker)
329  return;
330 
331  FloatPoint inslopeChange = data.inslopePoints[1] - FloatSize(data.inslopePoints[0].x(), data.inslopePoints[0].y());
332  FloatPoint outslopeChange = data.outslopePoints[1] - FloatSize(data.outslopePoints[0].x(), data.outslopePoints[0].y());
333 
334  double inslope = rad2deg(atan2(inslopeChange.y(), inslopeChange.x()));
335  double outslope = rad2deg(atan2(outslopeChange.y(), outslopeChange.x()));
336 
337  double angle = 0.0;
338  switch (data.type) {
339  case Start:
340  angle = outslope;
341  break;
342  case Mid:
343  angle = (inslope + outslope) / 2;
344  break;
345  case End:
346  angle = inslope;
347  }
348 
349  data.marker->draw(context, FloatRect(), data.origin.x(), data.origin.y(), data.strokeWidth, angle);
350 }
351 
352 static inline void updateMarkerDataForElement(MarkerData& previousMarkerData, const PathElement* element)
353 {
354  FloatPoint* points = element->points;
355 
356  switch (element->type) {
357  case PathElementAddQuadCurveToPoint:
358  // TODO
359  previousMarkerData.origin = points[1];
360  break;
361  case PathElementAddCurveToPoint:
362  previousMarkerData.inslopePoints[0] = points[1];
363  previousMarkerData.inslopePoints[1] = points[2];
364  previousMarkerData.origin = points[2];
365  break;
366  case PathElementMoveToPoint:
367  previousMarkerData.subpathStart = points[0];
368  case PathElementAddLineToPoint:
369  previousMarkerData.inslopePoints[0] = previousMarkerData.origin;
370  previousMarkerData.inslopePoints[1] = points[0];
371  previousMarkerData.origin = points[0];
372  break;
373  case PathElementCloseSubpath:
374  previousMarkerData.inslopePoints[0] = previousMarkerData.origin;
375  previousMarkerData.inslopePoints[1] = points[0];
376  previousMarkerData.origin = previousMarkerData.subpathStart;
377  previousMarkerData.subpathStart = FloatPoint();
378  }
379 }
380 
381 static void drawStartAndMidMarkers(void* info, const PathElement* element)
382 {
383  DrawMarkersData& data = *reinterpret_cast<DrawMarkersData*>(info);
384 
385  int elementIndex = data.elementIndex;
386  MarkerData& previousMarkerData = data.previousMarkerData;
387 
388  FloatPoint* points = element->points;
389 
390  // First update the outslope for the previous element
391  previousMarkerData.outslopePoints[0] = previousMarkerData.origin;
392  previousMarkerData.outslopePoints[1] = points[0];
393 
394  // Draw the marker for the previous element
395  if (elementIndex != 0)
396  drawMarkerWithData(data.context, previousMarkerData);
397 
398  // Update our marker data for this element
399  updateMarkerDataForElement(previousMarkerData, element);
400 
401  if (elementIndex == 1) {
402  // After drawing the start marker, switch to drawing mid markers
403  previousMarkerData.marker = data.midMarker;
404  previousMarkerData.type = Mid;
405  }
406 
407  data.elementIndex++;
408 }
409 
410 FloatRect RenderPath::drawMarkersIfNeeded(GraphicsContext* context, const FloatRect& rect, const Path& path) const
411 {
412  Document* doc = document();
413 
414  SVGElement* svgElement = static_cast<SVGElement*>(element());
415  ASSERT(svgElement && svgElement->document() && svgElement->isStyled());
416 
417  SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement);
418  const SVGRenderStyle* svgStyle = style()->svgStyle();
419 
420  AtomicString startMarkerId(SVGURIReference::getTarget(svgStyle->startMarker()));
421  AtomicString midMarkerId(SVGURIReference::getTarget(svgStyle->midMarker()));
422  AtomicString endMarkerId(SVGURIReference::getTarget(svgStyle->endMarker()));
423 
424  SVGResourceMarker* startMarker = getMarkerById(doc, startMarkerId);
425  SVGResourceMarker* midMarker = getMarkerById(doc, midMarkerId);
426  SVGResourceMarker* endMarker = getMarkerById(doc, endMarkerId);
427 
428  if (!startMarker && !startMarkerId.isEmpty())
429  svgElement->document()->accessSVGExtensions()->addPendingResource(startMarkerId, styledElement);
430  else if (startMarker)
431  startMarker->addClient(styledElement);
432 
433  if (!midMarker && !midMarkerId.isEmpty())
434  svgElement->document()->accessSVGExtensions()->addPendingResource(midMarkerId, styledElement);
435  else if (midMarker)
436  midMarker->addClient(styledElement);
437 
438  if (!endMarker && !endMarkerId.isEmpty())
439  svgElement->document()->accessSVGExtensions()->addPendingResource(endMarkerId, styledElement);
440  else if (endMarker)
441  endMarker->addClient(styledElement);
442 
443  if (!startMarker && !midMarker && !endMarker)
444  return FloatRect();
445 
446  double strokeWidth = SVGRenderStyle::cssPrimitiveToLength(this, svgStyle->strokeWidth(), 1.0f);
447  DrawMarkersData data(context, startMarker, midMarker, strokeWidth);
448 
449  path.apply(&data, drawStartAndMidMarkers);
450 
451  data.previousMarkerData.marker = endMarker;
452  data.previousMarkerData.type = End;
453  drawMarkerWithData(context, data.previousMarkerData);
454 
455  // We know the marker boundaries, only after they're drawn!
456  // Otherwhise we'd need to do all the marker calculation twice
457  // once here (through paint()) and once in absoluteClippedOverflowRect().
458  FloatRect bounds;
459 
460  if (startMarker)
461  bounds.unite(startMarker->cachedBounds());
462 
463  if (midMarker)
464  bounds.unite(midMarker->cachedBounds());
465 
466  if (endMarker)
467  bounds.unite(endMarker->cachedBounds());
468 
469  return bounds;
470 }*/
471 
472 }
473 
474 #endif // ENABLE(SVG)
QFuture< void > filter(Sequence &sequence, KeepFunctor filterFunction)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:48:09 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.