Changeset 258118 in webkit
- Timestamp:
- Mar 8, 2020, 4:13:45 PM (6 years ago)
- Location:
- trunk/Source
- Files:
-
- 1 added
- 15 edited
-
WTF/ChangeLog (modified) (1 diff)
-
WTF/wtf/PlatformEnable.h (modified) (1 diff)
-
WebCore/ChangeLog (modified) (1 diff)
-
WebCore/Headers.cmake (modified) (1 diff)
-
WebCore/WebCore.xcodeproj/project.pbxproj (modified) (4 diffs)
-
WebCore/platform/graphics/InlinePathData.h (added)
-
WebCore/platform/graphics/Path.cpp (modified) (3 diffs)
-
WebCore/platform/graphics/Path.h (modified) (8 diffs)
-
WebCore/platform/graphics/cairo/PathCairo.cpp (modified) (8 diffs)
-
WebCore/platform/graphics/cg/PathCG.cpp (modified) (10 diffs)
-
WebCore/platform/graphics/displaylists/DisplayListItems.cpp (modified) (1 diff)
-
WebCore/platform/graphics/displaylists/DisplayListItems.h (modified) (1 diff)
-
WebCore/platform/graphics/win/PathDirect2D.cpp (modified) (8 diffs)
-
WebKit/ChangeLog (modified) (1 diff)
-
WebKit/Platform/IPC/ArgumentCoders.cpp (modified) (1 diff)
-
WebKit/Platform/IPC/ArgumentCoders.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WTF/ChangeLog
r258089 r258118 1 2020-03-08 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 Lazily generate CGPaths for some simple types of paths, such as arcs and lines 4 https://bugs.webkit.org/show_bug.cgi?id=208464 5 <rdar://problem/59963226> 6 7 Reviewed by Daniel Bates, Darin Adler and Tim Horton. 8 9 Add a feature flag for INLINE_PATH_DATA. This feature flag exists to ensure that we can avoid having 10 m_inlineData on Path in ports that don't implement the necessary facilities for inline path data yet, since it 11 would just end up being wasted memory. 12 13 * wtf/PlatformEnable.h: 14 1 15 2020-03-07 Daniel Bates <dabates@apple.com> 2 16 -
trunk/Source/WTF/wtf/PlatformEnable.h
r258076 r258118 818 818 #endif 819 819 820 #if !defined(ENABLE_INLINE_PATH_DATA) && USE(CG) 821 #define ENABLE_INLINE_PATH_DATA 1 822 #endif 820 823 821 824 /* Disable SharedArrayBuffers until Spectre security concerns are mitigated. */ -
trunk/Source/WebCore/ChangeLog
r258116 r258118 1 2020-03-08 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 Lazily generate CGPaths for some simple types of paths, such as arcs and lines 4 https://bugs.webkit.org/show_bug.cgi?id=208464 5 <rdar://problem/59963226> 6 7 Reviewed by Daniel Bates, Darin Adler and Tim Horton. 8 9 When the GPU process is enabled and used to render the canvas element, some canvas-related subtests in 10 MotionMark see significant performance regressions. One of the reasons for this is that in the process of 11 decoding display list items that contain `WebCore::Path`s in the GPU process, we end up allocating a new CGPath 12 for each WebCore::Path. This dramatically increases page demand and memory usage in the GPU process in contrast 13 to shipping WebKit, due to the fact that all of these CGPaths allocated up-front, and must all exist somewhere 14 in the heap upon decoding the display list. 15 16 In contrast, in shipping WebKit, each call to stroke the current canvas path (i.e. invoking 17 GraphicsContext::strokePath) is succeeded by clearing the path, which deallocates the CGPath backing the WebCore 18 Path. The next time a CGPath needs to be created, CoreGraphics is free to then allocate the new CGPath at the 19 address of the previous CGPath which was just destroyed, which prevents us from dirtying more pages than 20 necessary. This phenomenon affects most of the canvas-related MotionMark subtests to some degree, though the 21 impact is most noticeable with Canvas Lines. 22 23 On top of all this, a significant portion of time is also spent calling CGPathApply and converting the resulting 24 CGPathElements into serializable data when encoding each WebCore Path. 25 26 To mitigate these two issues and restore the wins we get from memory locality when drawing paths in large 27 quantities, we can: 28 29 1. In the case of simple paths, stuff some information about how each path was created as inline data on 30 WebCore::Path itself, as a new data member. For now, this only encompasses lines, arcs, and moves (Paths 31 where only `Path::moveTo` was invoked), but may be expanded in the future to include ellipses and rects. 32 This allows us to achieve two things: (a) make encoding cheaper by not requiring a walk through all of 33 CGPath's elements, and (b) make decoding cheaper by just initializing the Path using inline data, rather 34 than having to create a new CGPath. 35 36 2. When painting the StrokePath display list item, just discard `m_path` after we're done painting with it. 37 This, in conjunction with (1), means that the CGPath backing the WebCore::Path in the GPU process is only 38 created when we're just about to paint (i.e. when calling into strokePath()), and destroyed right after 39 we're done painting with it. 40 41 See below for details. There should be no change in behavior. 42 43 * Headers.cmake: 44 * WebCore.xcodeproj/project.pbxproj: 45 * platform/graphics/InlinePathData.h: Added. 46 (WebCore::MoveData::encode const): 47 (WebCore::MoveData::decode): 48 (WebCore::LineData::encode const): 49 (WebCore::LineData::decode): 50 (WebCore::ArcData::encode const): 51 (WebCore::ArcData::decode): 52 53 Introduce InlinePathData, a Variant of several different inline data types, each of which represents one simple 54 path type that is stored using only inline data. This includes line segments (a start point and an end point), 55 as well as arcs (which, in addition to a center and start and end angles) also includes an optional offset, 56 which represents the current position of the path at the time "addArc" was called. 57 58 For instance, in the following scenario, the path would have an arc that is offset by (100, 0); if filled, it 59 would result in a composite shape resembling a semicircle on top of a triangle: 60 61 path.moveTo(100, 0); 62 path.addArc(100, 100, 50, 0, PI, false); 63 context.fill(path); 64 65 When a Path is initialized (or after it is cleared), it starts off with neither a CGPath nor inline data. Moving 66 the path causes it to store inline MoveData; calling calling `addLineTo` or `addArc` then replaces the inline 67 data with either LineData or ArcData. 68 69 If, at any point, the path changes in a different way (i.e. neither line, arc, nor move), we clear out the 70 inline data and fall back to just representing the path data using the CGPath (m_path). 71 72 * platform/graphics/Path.cpp: 73 74 Refactor the following 10 methods: moveTo, addLineTo, addArc, isEmpty, currentPoint, apply, elementCount, 75 hasCurrentPoint, fastBoundingRect, and boundingRect such that their implementations are now in platform-agnostic 76 code in Path.cpp. Logic in this platform-agnostic code will generally attempt to use inline path data to compute 77 an answer (or apply the requested mutations) without having to initialize the platform path representation. 78 Failing this, we fall back to calling -SlowCase versions of these methods, which will exercise the appropriate 79 APIs on each platform. 80 81 (WebCore::Path::elementCountSlowCase const): 82 (WebCore::Path::apply const): 83 (WebCore::Path::isEmpty const): 84 (WebCore::Path::hasCurrentPoint const): 85 (WebCore::Path::currentPoint const): 86 (WebCore::Path::elementCount const): 87 (WebCore::Path::addArc): 88 (WebCore::Path::addLineTo): 89 (WebCore::Path::moveTo): 90 91 In the case of these three methods for mutating a path, if we've either only moved the path or haven't touched 92 it at all, we can get away with only updating our inline path data, and avoid creating a CGPath. 93 94 (WebCore::Path::boundingRect const): 95 (WebCore::Path::fastBoundingRect const): 96 (WebCore::Path::boundingRectFromInlineData const): 97 (WebCore::Path::polygonPathFromPoints): 98 * platform/graphics/Path.h: 99 (WebCore::Path::encode const): 100 (WebCore::Path::decode): 101 102 Teach Path::encode and Path::decode to respectively serialize and deserialize WebCore::Path by consulting only 103 the inline data, if it is present. For simple types of paths, this decreases the cost of both IPC encoding and 104 decoding, but adds a negligible amount of overhead in the case where the path is non-inline. 105 106 (WebCore::Path::hasInlineData const): 107 (WebCore::Path::hasAnyInlineData const): 108 (WebCore::Path::isNull const): Deleted. 109 * platform/graphics/cairo/PathCairo.cpp: 110 (WebCore::Path::isEmptySlowCase const): 111 (WebCore::Path::currentPointSlowCase const): 112 (WebCore::Path::moveToSlowCase): 113 (WebCore::Path::addLineToSlowCase): 114 (WebCore::Path::addArcSlowCase): 115 (WebCore::Path::boundingRectSlowCase const): 116 (WebCore::Path::applySlowCase const): 117 (WebCore::Path::fastBoundingRectSlowCase const): 118 (WebCore::Path::isNull const): 119 (WebCore::Path::isEmpty const): Deleted. 120 (WebCore::Path::hasCurrentPoint const): Deleted. 121 (WebCore::Path::currentPoint const): Deleted. 122 (WebCore::Path::moveTo): Deleted. 123 (WebCore::Path::addLineTo): Deleted. 124 (WebCore::Path::addArc): Deleted. 125 (WebCore::Path::boundingRect const): Deleted. 126 (WebCore::Path::apply const): Deleted. 127 * platform/graphics/cg/PathCG.cpp: 128 (WebCore::Path::createCGPath const): 129 130 Add a helper method that is invoked when the Path is asked for a CGPath. In this case, if there is inline data, 131 we need to lazily create the path and apply any inline path data we've accumulated. Once we're done applying the 132 inline data, set a flag (m_needsToApplyInlineData) to false to avoid re-applying inline data to the path. 133 134 (WebCore::Path::platformPath const): 135 (WebCore::Path::ensurePlatformPath): 136 137 When ensurePlatformPath is invoked, we are about to mutate our CGPath in such a way that it can't be expressed 138 in terms of inline data (at least, not with the changes in this patch). Clear out the inline path data in this 139 case, and apply the CGPath mutations that were previously stashed away in inline path data. 140 141 (WebCore::Path::isNull const): 142 143 A path is now considered null if it is not only missing a CGPath, but also does not have any inline path data. 144 This maintains the invariant that `isNull()` is true iff the `platformPath()` returns 0x0. 145 146 (WebCore::Path::Path): 147 (WebCore::Path::swap): 148 149 Update the constructors and `swap` helper method (used by assignment operators) to account for the new members. 150 151 (WebCore::Path::contains const): 152 (WebCore::Path::transform): 153 (WebCore::zeroRectIfNull): 154 (WebCore::Path::boundingRectSlowCase const): 155 (WebCore::Path::fastBoundingRectSlowCase const): 156 (WebCore::Path::moveToSlowCase): 157 (WebCore::Path::addLineToSlowCase): 158 (WebCore::Path::addArcSlowCase): 159 (WebCore::Path::clear): 160 161 When clearing Path, instead of setting `m_path` to a newly allocated CGPath, simply reset it to null. This 162 ensures that if we then apply some changes that can be expressed using only inline path data, we avoid having to 163 update the CGPath, and instead just update the inline path data. 164 165 (WebCore::Path::isEmptySlowCase const): 166 (WebCore::Path::currentPointSlowCase const): 167 (WebCore::Path::applySlowCase const): 168 (WebCore::Path::elementCountSlowCase const): 169 (WebCore::Path::boundingRect const): Deleted. 170 (WebCore::Path::fastBoundingRect const): Deleted. 171 (WebCore::Path::moveTo): Deleted. 172 (WebCore::Path::addLineTo): Deleted. 173 (WebCore::Path::addArc): Deleted. 174 (WebCore::Path::isEmpty const): Deleted. 175 (WebCore::Path::hasCurrentPoint const): Deleted. 176 (WebCore::Path::currentPoint const): Deleted. 177 (WebCore::Path::apply const): Deleted. 178 (WebCore::Path::elementCount const): Deleted. 179 * platform/graphics/displaylists/DisplayListItems.cpp: 180 (WebCore::DisplayList::StrokePath::apply const): 181 182 Throw out the current WebCore::Path after we're done painting with it (see (2) in the above ChangeLog entry). 183 184 * platform/graphics/displaylists/DisplayListItems.h: 185 * platform/graphics/win/PathDirect2D.cpp: 186 (WebCore::Path::boundingRectSlowCase const): 187 (WebCore::Path::fastBoundingRectSlowCase const): 188 (WebCore::Path::moveToSlowCase): 189 (WebCore::Path::addLineToSlowCase): 190 (WebCore::Path::addArcSlowCase): 191 (WebCore::Path::isEmptySlowCase const): 192 (WebCore::Path::currentPointSlowCase const): 193 (WebCore::Path::applySlowCase const): 194 (WebCore::Path::isNull const): 195 (WebCore::Path::boundingRect const): Deleted. 196 (WebCore::Path::fastBoundingRect const): Deleted. 197 (WebCore::Path::moveTo): Deleted. 198 (WebCore::Path::addLineTo): Deleted. 199 (WebCore::Path::addArc): Deleted. 200 (WebCore::Path::isEmpty const): Deleted. 201 (WebCore::Path::hasCurrentPoint const): Deleted. 202 (WebCore::Path::currentPoint const): Deleted. 203 (WebCore::Path::apply const): Deleted. 204 1 205 2020-03-08 Konstantin Tokarev <annulen@yandex.ru> 2 206 -
trunk/Source/WebCore/Headers.cmake
r258060 r258118 1128 1128 platform/graphics/InbandTextTrackPrivate.h 1129 1129 platform/graphics/InbandTextTrackPrivateClient.h 1130 platform/graphics/InlinePathData.h 1130 1131 platform/graphics/IntPoint.h 1131 1132 platform/graphics/IntPointHash.h -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r258115 r258118 4983 4983 F44A5F591FED38F2007F5944 /* LegacyNSPasteboardTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = F44A5F571FED3830007F5944 /* LegacyNSPasteboardTypes.h */; settings = {ATTRIBUTES = (Private, ); }; }; 4984 4984 F44EBBD91DB5D21400277334 /* StaticRange.h in Headers */ = {isa = PBXBuildFile; fileRef = F44EBBD81DB5D21400277334 /* StaticRange.h */; settings = {ATTRIBUTES = (Private, ); }; }; 4985 F45775CE241437D5002DF1A0 /* InlinePathData.h in Headers */ = {isa = PBXBuildFile; fileRef = F45775CD241437D5002DF1A0 /* InlinePathData.h */; settings = {ATTRIBUTES = (Private, ); }; }; 4985 4986 F45C231E1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h in Headers */ = {isa = PBXBuildFile; fileRef = F45C231C1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h */; settings = {ATTRIBUTES = (Private, ); }; }; 4986 4987 F46729281E0DE68500ACC3D8 /* ScrollSnapOffsetsInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = F46729251E0DE5AB00ACC3D8 /* ScrollSnapOffsetsInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 15474 15475 F44EBBD81DB5D21400277334 /* StaticRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticRange.h; sourceTree = "<group>"; }; 15475 15476 F44EBBDA1DB5DD9D00277334 /* StaticRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaticRange.cpp; sourceTree = "<group>"; }; 15477 F45775CD241437D5002DF1A0 /* InlinePathData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InlinePathData.h; sourceTree = "<group>"; }; 15476 15478 F45C231B1995B73B00A6E2E3 /* AxisScrollSnapOffsets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AxisScrollSnapOffsets.cpp; sourceTree = "<group>"; }; 15477 15479 F45C231C1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AxisScrollSnapOffsets.h; sourceTree = "<group>"; }; … … 25138 25140 07941793166EA04E009416C2 /* InbandTextTrackPrivate.h */, 25139 25141 07CE77D416712A6A00C55A47 /* InbandTextTrackPrivateClient.h */, 25142 F45775CD241437D5002DF1A0 /* InlinePathData.h */, 25140 25143 2D46F04D17B96FBD005647F0 /* IntPoint.cpp */, 25141 25144 B27535440B053814002CE64F /* IntPoint.h */, … … 30429 30432 6FE198172178397C00446F08 /* InlineLineBreaker.h in Headers */, 30430 30433 6F0CD695229ED32700C5994E /* InlineLineBuilder.h in Headers */, 30434 F45775CE241437D5002DF1A0 /* InlinePathData.h in Headers */, 30431 30435 6F360E5023999421001512A7 /* InlineSoftLineBreakItem.h in Headers */, 30432 30436 AA4C3A770B2B1679002334A2 /* InlineStyleSheetOwner.h in Headers */, -
trunk/Source/WebCore/platform/graphics/Path.cpp
r257918 r258118 56 56 #if !HAVE(CGPATH_GET_NUMBER_OF_ELEMENTS) 57 57 58 size_t Path::elementCount () const58 size_t Path::elementCountSlowCase() const 59 59 { 60 60 size_t numPoints = 0; … … 168 168 } 169 169 170 void Path::apply(const PathApplierFunction& function) const 171 { 172 if (isNull()) 173 return; 174 175 #if ENABLE(INLINE_PATH_DATA) 176 if (hasInlineData<MoveData>()) { 177 PathElement element; 178 element.type = PathElement::Type::MoveToPoint; 179 element.points[0] = WTF::get<MoveData>(m_inlineData).location; 180 function(element); 181 return; 182 } 183 184 if (hasInlineData<LineData>()) { 185 auto& line = WTF::get<LineData>(m_inlineData); 186 PathElement element; 187 element.type = PathElement::Type::MoveToPoint; 188 element.points[0] = line.start; 189 function(element); 190 element.type = PathElement::Type::AddLineToPoint; 191 element.points[0] = line.end; 192 function(element); 193 return; 194 } 195 #endif 196 197 applySlowCase(function); 198 } 199 200 bool Path::isEmpty() const 201 { 202 if (isNull()) 203 return true; 204 205 #if ENABLE(INLINE_PATH_DATA) 206 if (hasAnyInlineData()) 207 return false; 208 #endif 209 210 return isEmptySlowCase(); 211 } 212 213 bool Path::hasCurrentPoint() const 214 { 215 return !isEmpty(); 216 } 217 218 FloatPoint Path::currentPoint() const 219 { 220 if (isNull()) 221 return { }; 222 223 #if ENABLE(INLINE_PATH_DATA) 224 if (hasInlineData<MoveData>()) 225 return WTF::get<MoveData>(m_inlineData).location; 226 227 if (hasInlineData<LineData>()) 228 return WTF::get<LineData>(m_inlineData).end; 229 #endif 230 231 return currentPointSlowCase(); 232 } 233 234 size_t Path::elementCount() const 235 { 236 #if ENABLE(INLINE_PATH_DATA) 237 if (hasInlineData<MoveData>()) 238 return 1; 239 240 if (hasInlineData<LineData>()) 241 return 2; 242 #endif 243 244 return elementCountSlowCase(); 245 } 246 247 void Path::addArc(const FloatPoint& point, float radius, float startAngle, float endAngle, bool anticlockwise) 248 { 249 // Workaround for <rdar://problem/5189233> CGPathAddArc hangs or crashes when passed inf as start or end angle, 250 // as well as http://bugs.webkit.org/show_bug.cgi?id=16449, since cairo_arc() functions hang or crash when 251 // passed inf as radius or start/end angle. 252 if (!std::isfinite(radius) || !std::isfinite(startAngle) || !std::isfinite(endAngle)) 253 return; 254 255 #if ENABLE(INLINE_PATH_DATA) 256 if (isNull() || hasInlineData<MoveData>()) { 257 ArcData arc; 258 if (hasAnyInlineData()) { 259 arc.hasOffset = true; 260 arc.offset = WTF::get<MoveData>(m_inlineData).location; 261 } 262 arc.center = point; 263 arc.radius = radius; 264 arc.startAngle = startAngle; 265 arc.endAngle = endAngle; 266 // FIXME: Either ArcData::clockwise needs to be renamed to anticlockwise, or the last argument to 267 // Path::addArc needs to be renamed to clockwise. 268 arc.clockwise = anticlockwise; 269 m_inlineData = { WTFMove(arc) }; 270 return; 271 } 272 #endif 273 274 addArcSlowCase(point, radius, startAngle, endAngle, anticlockwise); 275 } 276 277 void Path::addLineTo(const FloatPoint& point) 278 { 279 #if ENABLE(INLINE_PATH_DATA) 280 if (isNull() || hasInlineData<MoveData>()) { 281 LineData line; 282 line.start = hasAnyInlineData() ? WTF::get<MoveData>(m_inlineData).location : FloatPoint(); 283 line.end = point; 284 m_inlineData = { WTFMove(line) }; 285 return; 286 } 287 #endif 288 289 addLineToSlowCase(point); 290 } 291 292 void Path::moveTo(const FloatPoint& point) 293 { 294 #if ENABLE(INLINE_PATH_DATA) 295 if (isNull() || hasInlineData<MoveData>()) { 296 m_inlineData = MoveData { point }; 297 return; 298 } 299 #endif 300 301 moveToSlowCase(point); 302 } 303 304 FloatRect Path::boundingRect() const 305 { 306 if (isNull()) 307 return { }; 308 309 #if ENABLE(INLINE_PATH_DATA) 310 if (auto rect = boundingRectFromInlineData()) 311 return *rect; 312 #endif 313 314 return boundingRectSlowCase(); 315 } 316 317 FloatRect Path::fastBoundingRect() const 318 { 319 if (isNull()) 320 return { }; 321 322 #if ENABLE(INLINE_PATH_DATA) 323 if (auto rect = boundingRectFromInlineData()) 324 return *rect; 325 #endif 326 327 return fastBoundingRectSlowCase(); 328 } 329 330 #if ENABLE(INLINE_PATH_DATA) 331 332 Optional<FloatRect> Path::boundingRectFromInlineData() const 333 { 334 if (hasInlineData<MoveData>()) 335 return FloatRect { }; 336 337 if (hasInlineData<LineData>()) { 338 FloatRect result; 339 auto& line = WTF::get<LineData>(m_inlineData); 340 result.fitToPoints(line.start, line.end); 341 return result; 342 } 343 344 return WTF::nullopt; 345 } 346 347 #endif 348 170 349 #if !USE(CG) && !USE(DIRECT2D) 171 350 Path Path::polygonPathFromPoints(const Vector<FloatPoint>& points) … … 181 360 path.closeSubpath(); 182 361 return path; 183 }184 185 FloatRect Path::fastBoundingRect() const186 {187 return boundingRect();188 362 } 189 363 #endif -
trunk/Source/WebCore/platform/graphics/Path.h
r257918 r258118 26 26 */ 27 27 28 #ifndef Path_h 29 #define Path_h 28 #pragma once 30 29 31 30 #include "FloatRect.h" 31 #include "InlinePathData.h" 32 32 #include "WindRule.h" 33 33 #include <wtf/FastMalloc.h> … … 148 148 149 149 WEBCORE_EXPORT void clear(); 150 bool isNull() const { return !m_path; }150 WEBCORE_EXPORT bool isNull() const; 151 151 bool isEmpty() const; 152 152 // Gets the current point of the current path, which is conceptually the final point reached by the path so far. 153 153 // Note the Path can be empty (isEmpty() == true) and still have a current point. 154 // FIXME: The above comment might need to be updated; on all supported platforms, the result of hasCurrentPoint() is identical 155 // to !isEmpty(). 154 156 bool hasCurrentPoint() const; 155 157 FloatPoint currentPoint() const; … … 186 188 PlatformPathPtr platformPath() const { return m_path.get(); } 187 189 #elif USE(CG) 188 PlatformPathPtr platformPath() const { return m_path.get(); }190 WEBCORE_EXPORT PlatformPathPtr platformPath() const; 189 191 #else 190 192 PlatformPathPtr platformPath() const { return m_path; } … … 226 228 227 229 private: 230 #if ENABLE(INLINE_PATH_DATA) 231 template<typename DataType> bool hasInlineData() const; 232 bool hasAnyInlineData() const; 233 Optional<FloatRect> boundingRectFromInlineData() const; 234 #endif 235 236 void moveToSlowCase(const FloatPoint&); 237 void addLineToSlowCase(const FloatPoint&); 238 void addArcSlowCase(const FloatPoint&, float radius, float startAngle, float endAngle, bool anticlockwise); 239 240 FloatRect boundingRectSlowCase() const; 241 FloatRect fastBoundingRectSlowCase() const; 242 bool isEmptySlowCase() const; 243 FloatPoint currentPointSlowCase() const; 244 size_t elementCountSlowCase() const; 245 void applySlowCase(const PathApplierFunction&) const; 246 228 247 #if USE(CG) 248 void createCGPath() const; 229 249 void swap(Path&); 230 250 #endif … … 238 258 #endif 239 259 260 #if ENABLE(INLINE_PATH_DATA) 261 InlinePathData m_inlineData; 262 #endif 240 263 #if USE(CG) 241 264 mutable bool m_copyPathBeforeMutation { false }; … … 247 270 template<class Encoder> void Path::encode(Encoder& encoder) const 248 271 { 272 #if ENABLE(INLINE_PATH_DATA) 273 bool hasInlineData = hasAnyInlineData(); 274 encoder << hasInlineData; 275 if (hasInlineData) { 276 encoder << m_inlineData; 277 return; 278 } 279 #endif 280 249 281 encoder << static_cast<uint64_t>(elementCount()); 250 282 … … 277 309 { 278 310 Path path; 311 312 #if ENABLE(INLINE_PATH_DATA) 313 bool hasInlineData; 314 if (!decoder.decode(hasInlineData)) 315 return WTF::nullopt; 316 317 if (hasInlineData) { 318 if (!decoder.decode(path.m_inlineData)) 319 return WTF::nullopt; 320 321 return path; 322 } 323 #endif 324 279 325 uint64_t numPoints; 280 326 if (!decoder.decode(numPoints)) … … 340 386 } 341 387 342 } 343 344 #endif 388 #if ENABLE(INLINE_PATH_DATA) 389 390 template <typename DataType> inline bool Path::hasInlineData() const 391 { 392 return WTF::holds_alternative<DataType>(m_inlineData); 393 } 394 395 inline bool Path::hasAnyInlineData() const 396 { 397 return !hasInlineData<Monostate>(); 398 } 399 400 #endif 401 402 } // namespace WebCore -
trunk/Source/WebCore/platform/graphics/cairo/PathCairo.cpp
r255559 r258118 118 118 } 119 119 120 bool Path::isEmpty() const 121 { 122 return isNull() || !cairo_has_current_point(platformPath()->context()); 123 } 124 125 bool Path::hasCurrentPoint() const 126 { 127 return !isEmpty(); 128 } 129 130 FloatPoint Path::currentPoint() const 131 { 132 if (isNull()) 133 return FloatPoint(); 134 120 bool Path::isEmptySlowCase() const 121 { 122 return !cairo_has_current_point(platformPath()->context()); 123 } 124 125 FloatPoint Path::currentPointSlowCase() const 126 { 135 127 // FIXME: Is this the correct way? 136 128 double x; … … 146 138 } 147 139 148 void Path::moveTo (const FloatPoint& p)140 void Path::moveToSlowCase(const FloatPoint& p) 149 141 { 150 142 cairo_t* cr = ensurePlatformPath()->context(); … … 152 144 } 153 145 154 void Path::addLineTo (const FloatPoint& p)146 void Path::addLineToSlowCase(const FloatPoint& p) 155 147 { 156 148 cairo_t* cr = ensurePlatformPath()->context(); … … 190 182 } 191 183 192 void Path::addArc(const FloatPoint& p, float r, float startAngle, float endAngle, bool anticlockwise) 193 { 194 // http://bugs.webkit.org/show_bug.cgi?id=16449 195 // cairo_arc() functions hang or crash when passed inf as radius or start/end angle 196 if (!std::isfinite(r) || !std::isfinite(startAngle) || !std::isfinite(endAngle)) 197 return; 198 184 void Path::addArcSlowCase(const FloatPoint& p, float r, float startAngle, float endAngle, bool anticlockwise) 185 { 199 186 cairo_t* cr = ensurePlatformPath()->context(); 200 187 float sweep = endAngle - startAngle; … … 354 341 } 355 342 356 FloatRect Path::boundingRect() const 357 { 358 // Should this be isEmpty() or can an empty path have a non-zero origin? 359 if (isNull()) 360 return FloatRect(); 361 343 FloatRect Path::boundingRectSlowCase() const 344 { 362 345 cairo_t* cr = platformPath()->context(); 363 346 double x0, x1, y0, y1; … … 409 392 } 410 393 411 void Path::apply(const PathApplierFunction& function) const 412 { 413 if (isNull()) 414 return; 415 394 void Path::applySlowCase(const PathApplierFunction& function) const 395 { 416 396 cairo_t* cr = platformPath()->context(); 417 397 auto pathCopy = cairo_copy_path(cr); … … 448 428 } 449 429 430 FloatRect Path::fastBoundingRectSlowCase() const 431 { 432 return boundingRect(); 433 } 434 450 435 void Path::transform(const AffineTransform& transform) 451 436 { … … 456 441 } 457 442 443 bool Path::isNull() const 444 { 445 return !m_path; 446 } 447 458 448 } // namespace WebCore 459 449 -
trunk/Source/WebCore/platform/graphics/cg/PathCG.cpp
r257918 r258118 82 82 } 83 83 84 void Path::createCGPath() const 85 { 86 if (m_path) 87 return; 88 89 m_path = adoptCF(CGPathCreateMutable()); 90 91 WTF::switchOn(m_inlineData, 92 [&](Monostate) { }, // Start with an empty path. 93 [&](const MoveData& move) { 94 CGPathMoveToPoint(m_path.get(), nullptr, move.location.x(), move.location.y()); 95 }, 96 [&](const LineData& line) { 97 CGPathMoveToPoint(m_path.get(), nullptr, line.start.x(), line.start.y()); 98 CGPathAddLineToPoint(m_path.get(), nullptr, line.end.x(), line.end.y()); 99 }, 100 [&](const ArcData& arc) { 101 if (arc.hasOffset) 102 CGPathMoveToPoint(m_path.get(), nullptr, arc.offset.x(), arc.offset.y()); 103 CGPathAddArc(m_path.get(), nullptr, arc.center.x(), arc.center.y(), arc.radius, arc.startAngle, arc.endAngle, arc.clockwise); 104 } 105 ); 106 } 107 84 108 Path::Path(RetainPtr<CGMutablePathRef>&& path) 85 109 : m_path(WTFMove(path)) … … 90 114 Path::~Path() = default; 91 115 116 PlatformPathPtr Path::platformPath() const 117 { 118 if (!m_path && hasAnyInlineData()) 119 createCGPath(); 120 return m_path.get(); 121 } 122 92 123 PlatformPathPtr Path::ensurePlatformPath() 93 124 { 94 if (!m_path) 95 m_path = adoptCF(CGPathCreateMutable()); 96 else if (m_copyPathBeforeMutation) { 125 createCGPath(); 126 if (m_copyPathBeforeMutation) { 97 127 if (CFGetRetainCount(m_path.get()) > 1) 98 128 m_path = adoptCF(CGPathCreateMutableCopy(m_path.get())); 99 129 m_copyPathBeforeMutation = false; 100 130 } 131 m_inlineData = Monostate { }; 101 132 return m_path.get(); 102 133 } 103 134 135 bool Path::isNull() const 136 { 137 return !m_path && !hasAnyInlineData(); 138 } 139 104 140 Path::Path(const Path& other) 105 141 { 106 142 m_path = { other.m_path }; 143 m_inlineData = other.m_inlineData; 107 144 if (m_path) { 108 145 m_copyPathBeforeMutation = true; … … 113 150 Path::Path(Path&& other) 114 151 : m_path(std::exchange(other.m_path, nullptr)) 152 , m_inlineData(std::exchange(other.m_inlineData, Monostate { })) 115 153 , m_copyPathBeforeMutation(std::exchange(other.m_copyPathBeforeMutation, false)) 116 154 { … … 120 158 { 121 159 std::swap(m_path, otherPath.m_path); 160 std::swap(m_inlineData, otherPath.m_inlineData); 122 161 std::swap(m_copyPathBeforeMutation, otherPath.m_copyPathBeforeMutation); 123 162 } … … 180 219 181 220 // CGPathContainsPoint returns false for non-closed paths, as a work-around, we copy and close the path first. Radar 4758998 asks for a better CG API to use 182 auto path = adoptCF(copyCGPathClosingSubpaths( m_path.get()));221 auto path = adoptCF(copyCGPathClosingSubpaths(platformPath())); 183 222 bool ret = CGPathContainsPoint(path.get(), 0, point, rule == WindRule::EvenOdd ? true : false); 184 223 return ret; … … 218 257 #if PLATFORM(WIN) 219 258 auto path = adoptCF(CGPathCreateMutable()); 220 CGPathAddPath(path.get(), &transformCG, m_path.get());259 CGPathAddPath(path.get(), &transformCG, platformPath()); 221 260 #else 222 auto path = adoptCF(CGPathCreateMutableCopyByTransformingPath( m_path.get(), &transformCG));261 auto path = adoptCF(CGPathCreateMutableCopyByTransformingPath(platformPath(), &transformCG)); 223 262 #endif 224 263 m_path = WTFMove(path); 225 264 m_copyPathBeforeMutation = false; 226 } 227 228 FloatRect Path::boundingRect() const 229 { 230 if (isNull()) 231 return CGRectZero; 232 265 m_inlineData = Monostate { }; 266 } 267 268 static inline FloatRect zeroRectIfNull(CGRect rect) 269 { 270 if (CGRectIsNull(rect)) 271 return { }; 272 return rect; 273 } 274 275 FloatRect Path::boundingRectSlowCase() const 276 { 233 277 // CGPathGetBoundingBox includes the path's control points, CGPathGetPathBoundingBox does not. 234 235 CGRect bound = CGPathGetPathBoundingBox(m_path.get()); 236 return CGRectIsNull(bound) ? CGRectZero : bound; 237 } 238 239 FloatRect Path::fastBoundingRect() const 240 { 241 if (isNull()) 242 return CGRectZero; 243 CGRect bound = CGPathGetBoundingBox(m_path.get()); 244 return CGRectIsNull(bound) ? CGRectZero : bound; 278 return zeroRectIfNull(CGPathGetPathBoundingBox(platformPath())); 279 } 280 281 FloatRect Path::fastBoundingRectSlowCase() const 282 { 283 return zeroRectIfNull(CGPathGetBoundingBox(platformPath())); 245 284 } 246 285 … … 268 307 } 269 308 270 void Path::moveTo (const FloatPoint& point)309 void Path::moveToSlowCase(const FloatPoint& point) 271 310 { 272 311 CGPathMoveToPoint(ensurePlatformPath(), nullptr, point.x(), point.y()); 273 312 } 274 313 275 void Path::addLineTo (const FloatPoint& p)314 void Path::addLineToSlowCase(const FloatPoint& p) 276 315 { 277 316 CGPathAddLineToPoint(ensurePlatformPath(), nullptr, p.x(), p.y()); … … 351 390 } 352 391 353 void Path::addArc(const FloatPoint& p, float radius, float startAngle, float endAngle, bool clockwise) 354 { 355 // Workaround for <rdar://problem/5189233> CGPathAddArc hangs or crashes when passed inf as start or end angle 356 if (!std::isfinite(startAngle) || !std::isfinite(endAngle)) 357 return; 358 392 void Path::addArcSlowCase(const FloatPoint& p, float radius, float startAngle, float endAngle, bool clockwise) 393 { 359 394 CGPathAddArc(ensurePlatformPath(), nullptr, p.x(), p.y(), radius, startAngle, endAngle, clockwise); 360 395 } … … 403 438 return; 404 439 405 m_path = adoptCF(CGPathCreateMutable()); 440 m_path.clear(); 441 m_inlineData = Monostate { }; 406 442 m_copyPathBeforeMutation = false; 407 443 } 408 444 409 bool Path::isEmpty() const 410 { 411 return isNull() || CGPathIsEmpty(m_path.get()); 412 } 413 414 bool Path::hasCurrentPoint() const 415 { 416 return !isEmpty(); 417 } 418 419 FloatPoint Path::currentPoint() const 420 { 421 if (isNull()) 422 return FloatPoint(); 423 return CGPathGetCurrentPoint(m_path.get()); 445 bool Path::isEmptySlowCase() const 446 { 447 return CGPathIsEmpty(m_path.get()); 448 } 449 450 FloatPoint Path::currentPointSlowCase() const 451 { 452 return CGPathGetCurrentPoint(platformPath()); 424 453 } 425 454 … … 450 479 } 451 480 452 void Path::apply(const PathApplierFunction& function) const 453 { 454 if (isNull()) 455 return; 456 457 CGPathApply(m_path.get(), (void*)&function, CGPathApplierToPathApplier); 481 void Path::applySlowCase(const PathApplierFunction& function) const 482 { 483 CGPathApply(platformPath(), (void*)&function, CGPathApplierToPathApplier); 458 484 } 459 485 460 486 #if HAVE(CGPATH_GET_NUMBER_OF_ELEMENTS) 461 487 462 size_t Path::elementCount () const463 { 464 return CGPathGetNumberOfElements( m_path);488 size_t Path::elementCountSlowCase() const 489 { 490 return CGPathGetNumberOfElements(platformPath()); 465 491 } 466 492 -
trunk/Source/WebCore/platform/graphics/displaylists/DisplayListItems.cpp
r258051 r258118 1229 1229 void StrokePath::apply(GraphicsContext& context) const 1230 1230 { 1231 context.strokePath( m_path);1231 context.strokePath(WTFMove(m_path)); 1232 1232 } 1233 1233 -
trunk/Source/WebCore/platform/graphics/displaylists/DisplayListItems.h
r258051 r258118 2590 2590 Optional<FloatRect> localBounds(const GraphicsContext&) const override; 2591 2591 2592 constPath m_path;2592 mutable Path m_path; 2593 2593 }; 2594 2594 -
trunk/Source/WebCore/platform/graphics/win/PathDirect2D.cpp
r254087 r258118 302 302 } 303 303 304 FloatRect Path::boundingRect() const 305 { 306 if (isNull()) 307 return FloatRect(); 308 304 FloatRect Path::boundingRectSlowCase() const 305 { 309 306 D2D1_RECT_F bounds = { }; 310 307 if (!SUCCEEDED(m_path->GetBounds(nullptr, &bounds))) … … 314 311 } 315 312 316 FloatRect Path::fastBoundingRect() const 317 { 318 if (isNull()) 319 return FloatRect(); 320 313 FloatRect Path::fastBoundingRectSlowCase() const 314 { 321 315 D2D1_RECT_F bounds = { }; 322 316 if (!SUCCEEDED(m_path->GetBounds(nullptr, &bounds))) … … 375 369 } 376 370 377 void Path::moveTo (const FloatPoint& point)371 void Path::moveToSlowCase(const FloatPoint& point) 378 372 { 379 373 if (m_activePath) … … 395 389 } 396 390 397 void Path::addLineTo (const FloatPoint& point)391 void Path::addLineToSlowCase(const FloatPoint& point) 398 392 { 399 393 openFigureAtCurrentPointIfNecessary(); … … 526 520 } 527 521 528 void Path::addArc (const FloatPoint& center, float radius, float startAngle, float endAngle, bool anticlockwise)522 void Path::addArcSlowCase(const FloatPoint& center, float radius, float startAngle, float endAngle, bool anticlockwise) 529 523 { 530 524 auto arcStartPoint = arcStart(center, radius, startAngle); … … 622 616 } 623 617 624 bool Path::isEmpty() const 625 { 626 if (isNull()) 627 return true; 628 618 bool Path::isEmptySlowCase() const 619 { 629 620 if (!m_path->GetSourceGeometryCount()) 630 621 return true; … … 635 626 } 636 627 637 bool Path::hasCurrentPoint() const 638 { 639 return !isEmpty(); 640 } 641 642 FloatPoint Path::currentPoint() const 643 { 644 if (isNull()) 645 return FloatPoint(); 646 628 FloatPoint Path::currentPointSlowCase() const 629 { 647 630 float length = 0; 648 631 HRESULT hr = m_path->ComputeLength(nullptr, &length); … … 669 652 } 670 653 671 void Path::apply(const PathApplierFunction& function) const 672 { 673 if (isNull()) 674 return; 675 654 void Path::applySlowCase(const PathApplierFunction&) const 655 { 676 656 notImplemented(); 677 657 } 678 658 659 bool Path::isNull() const 660 { 661 return !m_path; 662 } 663 679 664 } 680 665 -
trunk/Source/WebKit/ChangeLog
r258117 r258118 1 2020-03-08 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 Lazily generate CGPaths for some simple types of paths, such as arcs and lines 4 https://bugs.webkit.org/show_bug.cgi?id=208464 5 <rdar://problem/59963226> 6 7 Reviewed by Daniel Bates, Darin Adler and Tim Horton. 8 9 Add argument coders for `WTF::Monostate`, so that Variants of the form: `Variant<Monostate, Foo, Bar>` can be 10 encoded and decoded over IPC. 11 12 * Platform/IPC/ArgumentCoders.cpp: 13 (IPC::ArgumentCoder<Monostate>::encode): 14 (IPC::ArgumentCoder<Monostate>::decode): 15 * Platform/IPC/ArgumentCoders.h: 16 1 17 2020-03-08 Brady Eidson <beidson@apple.com> 2 18 -
trunk/Source/WebKit/Platform/IPC/ArgumentCoders.cpp
r250673 r258118 206 206 #endif 207 207 208 void ArgumentCoder<Monostate>::encode(Encoder&, const Monostate&) 209 { 210 } 211 212 Optional<Monostate> ArgumentCoder<Monostate>::decode(Decoder&) 213 { 214 return Monostate { }; 215 } 216 208 217 } // namespace IPC -
trunk/Source/WebKit/Platform/IPC/ArgumentCoders.h
r256632 r258118 34 34 #include <wtf/SHA1.h> 35 35 #include <wtf/Unexpected.h> 36 #include <wtf/Variant.h> 36 37 #include <wtf/WallTime.h> 37 38 … … 692 693 #endif 693 694 695 template<> struct ArgumentCoder<Monostate> { 696 static void encode(Encoder&, const Monostate&); 697 static Optional<Monostate> decode(Decoder&); 698 }; 699 694 700 } // namespace IPC
Note:
See TracChangeset
for help on using the changeset viewer.