Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/skia/./../../../gfx/skia/skia/src/core/SkEdgeBuilder.cpp
Warning:line 227, column 9
Value stored to 'maxEdgeCount' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_gfx_skia4.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/skia -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/skia -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_SKIA -D SKIA_IMPLEMENTATION=1 -D SK_PDF_USE_HARFBUZZ_SUBSET=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/gfx/skia -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/skia -I /root/firefox-clang/gfx/skia/skia -I /root/firefox-clang/gfx/harfbuzz/src -I /root/firefox-clang/gfx/cairo/cairo/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/pixman-1 -I /usr/include/sysprof-6 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -Wno-deprecated-declarations -Wno-overloaded-virtual -Wno-sign-compare -Wno-unreachable-code -Wno-unused-function -Wno-implicit-fallthrough -Wno-inconsistent-missing-override -Wno-macro-redefined -Wno-unused-private-field -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_gfx_skia4.cpp
1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/core/SkEdgeBuilder.h"
9
10#include "include/core/SkPath.h"
11#include "include/core/SkPoint.h"
12#include "include/core/SkTypes.h"
13#include "include/private/base/SkDebug.h"
14#include "include/private/base/SkFixed.h"
15#include "include/private/base/SkFloatingPoint.h"
16#include "include/private/base/SkSafe32.h"
17#include "src/base/SkSafeMath.h"
18#include "src/core/SkAnalyticEdge.h"
19#include "src/core/SkEdge.h"
20#include "src/core/SkEdgeClipper.h"
21#include "src/core/SkGeometry.h"
22#include "src/core/SkLineClipper.h"
23#include "src/core/SkPathPriv.h"
24
25SkEdgeBuilder::Combine SkBasicEdgeBuilder::combineVertical(const SkEdge* edge, SkEdge* last) {
26 // We only consider edges that were originally lines to be vertical to avoid numerical issues
27 // (crbug.com/1154864).
28 if (last->fEdgeType != SkEdge::Type::kLine || last->fDxDy || edge->fX != last->fX) {
29 return kNo_Combine;
30 }
31 if (edge->fWinding == last->fWinding) {
32 if (edge->fLastY + 1 == last->fFirstY) {
33 last->fFirstY = edge->fFirstY;
34 return kPartial_Combine;
35 }
36 if (edge->fFirstY == last->fLastY + 1) {
37 last->fLastY = edge->fLastY;
38 return kPartial_Combine;
39 }
40 return kNo_Combine;
41 }
42 if (edge->fFirstY == last->fFirstY) {
43 if (edge->fLastY == last->fLastY) {
44 return kTotal_Combine;
45 }
46 if (edge->fLastY < last->fLastY) {
47 last->fFirstY = edge->fLastY + 1;
48 return kPartial_Combine;
49 }
50 last->fFirstY = last->fLastY + 1;
51 last->fLastY = edge->fLastY;
52 last->fWinding = edge->fWinding;
53 return kPartial_Combine;
54 }
55 if (edge->fLastY == last->fLastY) {
56 if (edge->fFirstY > last->fFirstY) {
57 last->fLastY = edge->fFirstY - 1;
58 return kPartial_Combine;
59 }
60 last->fLastY = last->fFirstY - 1;
61 last->fFirstY = edge->fFirstY;
62 last->fWinding = edge->fWinding;
63 return kPartial_Combine;
64 }
65 return kNo_Combine;
66}
67
68SkEdgeBuilder::Combine SkAnalyticEdgeBuilder::combineVertical(const SkAnalyticEdge* edge,
69 SkAnalyticEdge* last) {
70 auto approximately_equal = [](SkFixed a, SkFixed b) {
71 return SkAbs32(a - b) < 0x100;
72 };
73
74 // We only consider edges that were originally lines to be vertical to avoid numerical issues
75 // (crbug.com/1154864).
76 if (last->fEdgeType != SkAnalyticEdge::Type::kLine || last->fDX || edge->fX != last->fX) {
77 return kNo_Combine;
78 }
79 if (edge->fWinding == last->fWinding) {
80 if (edge->fLowerY == last->fUpperY) {
81 last->fUpperY = edge->fUpperY;
82 last->fY = last->fUpperY;
83 return kPartial_Combine;
84 }
85 if (approximately_equal(edge->fUpperY, last->fLowerY)) {
86 last->fLowerY = edge->fLowerY;
87 return kPartial_Combine;
88 }
89 return kNo_Combine;
90 }
91 if (approximately_equal(edge->fUpperY, last->fUpperY)) {
92 if (approximately_equal(edge->fLowerY, last->fLowerY)) {
93 return kTotal_Combine;
94 }
95 if (edge->fLowerY < last->fLowerY) {
96 last->fUpperY = edge->fLowerY;
97 last->fY = last->fUpperY;
98 return kPartial_Combine;
99 }
100 last->fUpperY = last->fLowerY;
101 last->fY = last->fUpperY;
102 last->fLowerY = edge->fLowerY;
103 last->fWinding = edge->fWinding;
104 return kPartial_Combine;
105 }
106 if (approximately_equal(edge->fLowerY, last->fLowerY)) {
107 if (edge->fUpperY > last->fUpperY) {
108 last->fLowerY = edge->fUpperY;
109 return kPartial_Combine;
110 }
111 last->fLowerY = last->fUpperY;
112 last->fUpperY = edge->fUpperY;
113 last->fY = last->fUpperY;
114 last->fWinding = edge->fWinding;
115 return kPartial_Combine;
116 }
117 return kNo_Combine;
118}
119
120static bool is_vertical(const SkEdge* edge) {
121 // We only consider edges that were originally lines to be vertical to avoid numerical issues
122 // (crbug.com/1154864).
123 return edge->fDxDy == 0
124 && edge->fEdgeType == SkEdge::Type::kLine;
125}
126
127static bool is_vertical(const SkAnalyticEdge* edge) {
128 // We only consider edges that were originally lines to be vertical to avoid numerical issues
129 // (crbug.com/1154864).
130 return edge->fDX == 0
131 && edge->fEdgeType == SkAnalyticEdge::Type::kLine;
132}
133
134// TODO: we can deallocate the edge if edge->setFoo() fails
135// or when we don't use it (kPartial_Combine or kTotal_Combine).
136
137void SkBasicEdgeBuilder::addLine(const SkPoint pts[]) {
138 SkEdge* edge = fAlloc.make<SkEdge>();
139 if (edge->setLine(pts[0], pts[1])) {
140 Combine combine = is_vertical(edge) && !fList.empty()
141 ? this->combineVertical(edge, (SkEdge*)fList.back())
142 : kNo_Combine;
143
144 switch (combine) {
145 case kTotal_Combine: fList.pop_back(); break;
146 case kPartial_Combine: break;
147 case kNo_Combine: fList.push_back(edge); break;
148 }
149 }
150}
151void SkAnalyticEdgeBuilder::addLine(const SkPoint pts[]) {
152 SkAnalyticEdge* edge = fAlloc.make<SkAnalyticEdge>();
153 if (edge->setLine(pts[0], pts[1])) {
154
155 Combine combine = is_vertical(edge) && !fList.empty()
156 ? this->combineVertical(edge, (SkAnalyticEdge*)fList.back())
157 : kNo_Combine;
158
159 switch (combine) {
160 case kTotal_Combine: fList.pop_back(); break;
161 case kPartial_Combine: break;
162 case kNo_Combine: fList.push_back(edge); break;
163 }
164 }
165}
166void SkBasicEdgeBuilder::addQuad(const SkPoint pts[]) {
167 SkQuadraticEdge* edge = fAlloc.make<SkQuadraticEdge>();
168 if (edge->setQuadratic(pts)) {
169 fList.push_back(edge);
170 }
171}
172void SkAnalyticEdgeBuilder::addQuad(const SkPoint pts[]) {
173 SkAnalyticQuadraticEdge* edge = fAlloc.make<SkAnalyticQuadraticEdge>();
174 if (edge->setQuadratic(pts)) {
175 fList.push_back(edge);
176 }
177}
178
179void SkBasicEdgeBuilder::addCubic(const SkPoint pts[]) {
180 SkCubicEdge* edge = fAlloc.make<SkCubicEdge>();
181 if (edge->setCubic(pts)) {
182 fList.push_back(edge);
183 }
184}
185void SkAnalyticEdgeBuilder::addCubic(const SkPoint pts[]) {
186 SkAnalyticCubicEdge* edge = fAlloc.make<SkAnalyticCubicEdge>();
187 if (edge->setCubic(pts)) {
188 fList.push_back(edge);
189 }
190}
191
192// TODO: merge addLine() and addPolyLine()?
193
194SkEdgeBuilder::Combine SkAnalyticEdgeBuilder::addPolyLine(const SkPoint pts[],
195 char* arg_edge, char** arg_edgePtr) {
196 auto edge = (SkAnalyticEdge*) arg_edge;
197 auto edgePtr = (SkAnalyticEdge**)arg_edgePtr;
198
199 if (edge->setLine(pts[0], pts[1])) {
200 return is_vertical(edge) && edgePtr > (SkAnalyticEdge**)fEdgeList
201 ? this->combineVertical(edge, edgePtr[-1])
202 : kNo_Combine;
203 }
204 return SkEdgeBuilder::kPartial_Combine; // As above.
205}
206
207SkRect SkBasicEdgeBuilder::recoverClip(const SkIRect& src) const {
208 return SkRect::Make(src);
209}
210SkRect SkAnalyticEdgeBuilder::recoverClip(const SkIRect& src) const {
211 return SkRect::Make(src);
212}
213
214char* SkAnalyticEdgeBuilder::allocEdges(size_t n, size_t* size) {
215 *size = sizeof(SkAnalyticEdge);
216 return (char*)fAlloc.makeArrayDefault<SkAnalyticEdge>(n);
217}
218
219// TODO: maybe get rid of buildPoly() entirely?
220int SkEdgeBuilder::buildPoly(const SkPathRaw& raw, const SkIRect* iclip, bool canCullToTheRight) {
221 size_t maxEdgeCount = raw.fPoints.size();
222 if (iclip) {
223 // clipping can turn 1 line into (up to) kMaxClippedLineSegments, since
224 // we turn portions that are clipped out on the left/right into vertical
225 // segments.
226 SkSafeMath safe;
227 maxEdgeCount = safe.mul(maxEdgeCount, SkLineClipper::kMaxClippedLineSegments);
Value stored to 'maxEdgeCount' is never read
228 if (!safe) {
229 return 0;
230 }
231 }
232
233 SkPathEdgeIter iter(raw);
234 if (iclip) {
235 SkRect clip = this->recoverClip(*iclip);
236
237 while (auto e = iter.next()) {
238 switch (e.fEdge) {
239 case SkPathEdgeIter::Edge::kLine: {
240 SkPoint lines[SkLineClipper::kMaxPoints];
241 int lineCount = SkLineClipper::ClipLine(e.fPts, clip, lines, canCullToTheRight);
242 SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments)static_cast<void>( __builtin_expect(static_cast<bool
>(lineCount <= SkLineClipper::kMaxClippedLineSegments),
1) ? static_cast<void>(0) : []{ do { if (sk_abort_is_enabled
()) { do { SkDebugf("%s:%d" ": fatal error: \"" "check(%s)" "\"\n"
, "./../../../gfx/skia/skia/src/core/SkEdgeBuilder.cpp", 242,
"lineCount <= SkLineClipper::kMaxClippedLineSegments"); ;
sk_abort_no_print(); } while (false); } } while(false); }() )
;
243 for (int i = 0; i < lineCount; i++) {
244 this->addLine(lines + i);
245 }
246 break;
247 }
248 default:
249 SkDEBUGFAIL("unexpected verb")do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \""
"%s" "\"\n", "./../../../gfx/skia/skia/src/core/SkEdgeBuilder.cpp"
, 249, "unexpected verb"); ; sk_abort_no_print(); } while (false
); } } while(false)
;
250 break;
251 }
252 }
253 } else {
254 while (auto e = iter.next()) {
255 switch (e.fEdge) {
256 case SkPathEdgeIter::Edge::kLine: {
257 this->addLine(e.fPts);
258 break;
259 }
260 default:
261 SkDEBUGFAIL("unexpected verb")do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \""
"%s" "\"\n", "./../../../gfx/skia/skia/src/core/SkEdgeBuilder.cpp"
, 261, "unexpected verb"); ; sk_abort_no_print(); } while (false
); } } while(false)
;
262 break;
263 }
264 }
265 }
266 fEdgeList = fList.begin();
267 return fList.size();
268}
269
270int SkEdgeBuilder::build(const SkPathRaw& raw, const SkIRect* iclip, bool canCullToTheRight) {
271 if (iclip) {
272 SkRect clip = this->recoverClip(*iclip);
273 struct Rec {
274 SkEdgeBuilder* fBuilder;
275 bool fIsFinite;
276 } rec = { this, true };
277
278 SkEdgeClipper::ClipPath(raw, clip, canCullToTheRight,
279 [](SkEdgeClipper* clipper, bool, void* ctx) {
280 Rec* rec = (Rec*)ctx;
281 SkPoint pts[4];
282
283 while (auto verb = clipper->next(pts)) {
284 const int count = SkPathPriv::PtsInIter(*verb);
285 if (!SkIsFinite(&pts[0].fX, count*2)) {
286 rec->fIsFinite = false;
287 return;
288 }
289 switch (*verb) {
290 case SkPathVerb::kLine: rec->fBuilder->addLine (pts); break;
291 case SkPathVerb::kQuad: rec->fBuilder->addQuad (pts); break;
292 case SkPathVerb::kCubic: rec->fBuilder->addCubic(pts); break;
293 default: break;
294 }
295 }
296 }, &rec);
297 fEdgeList = fList.begin();
298 return rec.fIsFinite ? fList.size() : 0;
299 }
300
301 SkPathEdgeIter iter(raw);
302 SkAutoConicToQuads quadder;
303 constexpr float kConicTol = 0.25f;
304 SkPoint monoY[10];
305 SkPoint monoX[5];
306 auto handle_quad = [this, &monoX](const SkPoint pts[3]) {
307 int n = SkChopQuadAtYExtrema(pts, monoX);
308 for (int i = 0; i <= n; i++) {
309 this->addQuad(&monoX[i * 2]);
310 }
311 };
312
313 while (auto e = iter.next()) {
314 switch (e.fEdge) {
315 case SkPathEdgeIter::Edge::kLine:
316 this->addLine(e.fPts);
317 break;
318 case SkPathEdgeIter::Edge::kQuad: {
319 handle_quad(e.fPts);
320 break;
321 }
322 case SkPathEdgeIter::Edge::kConic: {
323 const SkPoint* quadPts =
324 quadder.computeQuads(e.fPts, iter.conicWeight(), kConicTol);
325 for (int i = 0; i < quadder.countQuads(); ++i) {
326 handle_quad(quadPts);
327 quadPts += 2;
328 }
329 } break;
330 case SkPathEdgeIter::Edge::kCubic: {
331 int n = SkChopCubicAtYExtrema(e.fPts, monoY);
332 for (int i = 0; i <= n; i++) {
333 this->addCubic(&monoY[i * 3]);
334 }
335 break;
336 }
337 default:
338 SkDEBUGFAIL("Unknown edge type")do { if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \""
"%s" "\"\n", "./../../../gfx/skia/skia/src/core/SkEdgeBuilder.cpp"
, 338, "Unknown edge type"); ; sk_abort_no_print(); } while (
false); } } while(false)
;
339 break;
340 }
341 }
342 fEdgeList = fList.begin();
343 return fList.size();
344}
345
346int SkEdgeBuilder::buildEdges(const SkPathRaw& raw,
347 const SkIRect* shiftedClip) {
348 // If we're convex, then we need both edges, even if the right edge is past the clip.
349 const bool canCullToTheRight = !raw.isKnownToBeConvex();
350
351 // We can use our buildPoly() optimization if all the segments are lines.
352 // (Edges are homogeneous and stored contiguously in memory, no need for indirection.)
353 const int count = SkPath::kLine_SegmentMask == raw.segmentMasks()
354 ? this->buildPoly(raw, shiftedClip, canCullToTheRight)
355 : this->build (raw, shiftedClip, canCullToTheRight);
356
357 SkASSERT(count >= 0)static_cast<void>( __builtin_expect(static_cast<bool
>(count >= 0), 1) ? static_cast<void>(0) : []{ do
{ if (sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \""
"check(%s)" "\"\n", "./../../../gfx/skia/skia/src/core/SkEdgeBuilder.cpp"
, 357, "count >= 0"); ; sk_abort_no_print(); } while (false
); } } while(false); }() )
;
358
359 // If we can't cull to the right, we should have count > 1 (or 0).
360 if (!canCullToTheRight) {
361 SkASSERT(count != 1)static_cast<void>( __builtin_expect(static_cast<bool
>(count != 1), 1) ? static_cast<void>(0) : []{ do { if
(sk_abort_is_enabled()) { do { SkDebugf("%s:%d" ": fatal error: \""
"check(%s)" "\"\n", "./../../../gfx/skia/skia/src/core/SkEdgeBuilder.cpp"
, 361, "count != 1"); ; sk_abort_no_print(); } while (false);
} } while(false); }() )
;
362 }
363 return count;
364}
365
366int SkEdgeBuilder::buildEdges(const SkPath& path, const SkIRect* shiftedClip) {
367 if (auto raw = SkPathPriv::Raw(path, SkResolveConvexity::kYes)) {
368 return buildEdges(*raw, shiftedClip);
369 }
370 return 0; // no edges were built
371}