xref: /aosp_15_r20/external/skia/site/docs/dev/contrib/style.md (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1---
2title: 'Coding Style Guidelines'
3linkTitle: 'Coding Style Guidelines'
4---
5
6These conventions have evolved over time. Some of the earlier code in both
7projects doesn't strictly adhere to the guidelines. However, as the code evolves
8we hope to make the existing code conform to the guildelines.
9
10## Files
11
12We use .cpp and .h as extensions for c++ source and header files.
13
14Headers that aren't meant for public consumption should be placed in src
15directories so that they aren't in a client's search path, or in include/private
16if they need to be used by public headers.
17
18We prefer to minimize includes. If forward declaring a name in a header is
19sufficient then that is preferred to an include.
20
21Forward declarations and file includes should be in alphabetical order.
22
23### No define before sktypes
24
25Do not use #if/#ifdef before including "SkTypes.h" (directly or indirectly).
26Most things you'd #if on tend to not yet be decided until SkTypes.h.
27
28We use 4 spaces, not tabs.
29
30We use Unix style endlines (LF).
31
32We prefer no trailing whitespace but aren't very strict about it.
33
34We wrap lines at 100 columns unless it is excessively ugly (use your judgement).
35
36## Naming
37
38Most externally visible types and functions use an Sk- prefix to designate
39they're part of Skia, but code in Ganesh uses Gr-. Nested types need not be
40prefixed.
41
42<!--?prettify?-->
43
44```
45class SkClass {
46public:
47    class HelperClass {
48        ...
49    };
50};
51```
52
53Data fields in structs, classes, and unions that have methods begin with
54lower-case f and are then camel-capped, to distinguish those fields from other
55variables. Types that are predominantly meant for direct field access don't need
56f-decoration.
57
58<!--?prettify?-->
59
60```
61struct GrCar {
62    float milesDriven;
63    Color color;
64};
65
66class GrMotorcyle {
67public:
68    float getMilesDriven() const { return fMilesDriven; }
69    void  setMilesDriven(float milesDriven) { fMilesDriven = milesDriven; }
70
71    Color getColor() const { return fColor; }
72private:
73    float fMilesDriven;
74    Color fColor;
75};
76```
77
78Global variables are similar but prefixed with g and camel-capped.
79
80<!--?prettify?-->
81
82```
83bool gLoggingEnabled;
84```
85
86Local variables and arguments are camel-capped with no initial cap.
87
88<!--?prettify?-->
89
90```
91int herdCats(const Array& cats) {
92    int numCats = cats.count();
93}
94```
95
96Variables declared `constexpr` or `const`, and whose value is fixed for the
97duration of the program, are named with a leading "k" and then camel-capped.
98
99<!--?prettify?-->
100
101```
102int drawPicture() {
103    constexpr SkISize kPictureSize = {100, 100};
104    constexpr float kZoom = 1.0f;
105}
106```
107
108Enum values are also prefixed with k. Unscoped enum values are postfixed with an
109underscore and singular name of the enum name. The enum itself should be
110singular for exclusive values or plural for a bitfield. If a count is needed it
111is `k<singular enum name>Count` and not be a member of the enum (see example),
112or a kLast member of the enum is fine too.
113
114<!--?prettify?-->
115
116```
117// Enum class does not need suffixes.
118enum class SkPancakeType {
119     kBlueberry,
120     kPlain,
121     kChocolateChip,
122};
123```
124
125<!--?prettify?-->
126
127```
128// Enum should have a suffix after the enum name.
129enum SkDonutType {
130     kGlazed_DonutType,
131     kSprinkles_DonutType,
132     kChocolate_DonutType,
133     kMaple_DonutType,
134
135     kLast_DonutType = kMaple_DonutType
136};
137
138static const SkDonutType kDonutTypeCount = kLast_DonutType + 1;
139```
140
141<!--?prettify?-->
142
143```
144enum SkSausageIngredientBits {
145    kFennel_SausageIngredientBit = 0x1,
146    kBeef_SausageIngredientBit   = 0x2
147};
148```
149
150<!--?prettify?-->
151
152```
153enum SkMatrixFlags {
154    kTranslate_MatrixFlag = 0x1,
155    kRotate_MatrixFlag    = 0x2
156};
157```
158
159Macros are all caps with underscores between words. Macros that have greater
160than file scope should be prefixed SK or GR.
161
162Static non-class functions in implementation files are lower-case with
163underscores separating words:
164
165<!--?prettify?-->
166
167```
168static inline bool tastes_like_chicken(Food food) {
169    return kIceCream_Food != food;
170}
171```
172
173Externed functions or static class functions are camel-capped with an initial
174cap:
175
176<!--?prettify?-->
177
178```
179bool SkIsOdd(int n);
180
181class SkFoo {
182public:
183    static int FooInstanceCount();
184
185    // Not static.
186    int barBaz();
187};
188```
189
190## Macros
191
192Ganesh macros that are GL-specific should be prefixed GR_GL.
193
194<!--?prettify?-->
195
196```
197#define GR_GL_TEXTURE0 0xdeadbeef
198```
199
200Ganesh prefers that macros are always defined and the use of `#if MACRO` rather
201than `#ifdef MACRO`.
202
203<!--?prettify?-->
204
205```
206#define GR_GO_SLOWER 0
207...
208#if GR_GO_SLOWER
209    Sleep(1000);
210#endif
211```
212
213The rest of Skia tends to use `#ifdef SK_MACRO` for boolean flags.
214
215## Braces
216
217Open braces don't get a newline. `else` and `else if` appear on same line as
218opening and closing braces unless preprocessor conditional compilation
219interferes. Braces are always used with `if`, `else`, `while`, `for`, and `do`.
220
221<!--?prettify?-->
222
223```
224if (...) {
225    oneOrManyLines;
226}
227
228if (...) {
229    oneOrManyLines;
230} else if (...) {
231    oneOrManyLines;
232} else {
233    oneOrManyLines;
234}
235
236for (...) {
237    oneOrManyLines;
238}
239
240while (...) {
241    oneOrManyLines;
242}
243
244void function(...) {
245    oneOrManyLines;
246}
247
248if (!error) {
249    proceed_as_usual();
250}
251#if HANDLE_ERROR
252else {
253    freak_out();
254}
255#endif
256```
257
258## Flow Control
259
260There is a space between flow control words and parentheses, and between
261parentheses and braces:
262
263<!--?prettify?-->
264
265```
266while (...) {
267}
268
269do {
270} while (...);
271
272switch (...) {
273...
274}
275```
276
277Cases and default in switch statements are indented from the switch.
278
279<!--?prettify?-->
280
281```
282switch (color) {
283    case kBlue:
284        ...
285        break;
286    case kGreen:
287        ...
288        break;
289    ...
290    default:
291       ...
292       break;
293}
294```
295
296Fallthrough from one case to the next is annotated with `[[fallthrough]]`.
297However, when multiple case statements in a row are used, they do not need the
298`[[fallthrough]]` annotation.
299
300<!--?prettify?-->
301
302```
303switch (recipe) {
304    ...
305    case kSmallCheesePizza_Recipe:
306    case kLargeCheesePizza_Recipe:
307        ingredients |= kCheese_Ingredient | kDough_Ingredient | kSauce_Ingredient;
308        break;
309    case kCheeseOmelette_Recipe:
310        ingredients |= kCheese_Ingredient;
311        [[fallthrough]]
312    case kPlainOmelette_Recipe:
313        ingredients |= (kEgg_Ingredient | kMilk_Ingredient);
314        break;
315    ...
316}
317```
318
319When a block is needed to declare variables within a case follow this pattern:
320
321<!--?prettify?-->
322
323```
324switch (filter) {
325    ...
326    case kGaussian_Filter: {
327        Bitmap srcCopy = src->makeCopy();
328        ...
329    } break;
330    ...
331};
332```
333
334## Classes
335
336Unless there is a need for forward declaring something, class declarations
337should be ordered `public`, `protected`, `private`. Each should be preceded by a
338newline. Within each visibility section (`public`, `private`), fields should not
339be intermixed with methods. It's nice to keep all data fields together at the
340end.
341
342<!--?prettify?-->
343
344```
345class SkFoo {
346
347public:
348    ...
349
350protected:
351    ...
352
353private:
354    void barHelper(...);
355    ...
356
357    SkBar fBar;
358    ...
359};
360```
361
362Virtual functions that are overridden in derived classes should use override,
363and the virtual keyword should be omitted.
364
365<!--?prettify?-->
366
367```
368void myVirtual() override {
369}
370```
371
372If you call a method on a parent type that must stand out as specifically the
373parent's version of that method, such as `Parent::method()`. The `this->` that
374would normally be required before a method call on the current object is not
375necessary when using a scope qualifier.
376
377<!--?prettify?-->
378
379```
380class GrDillPickle : public GrPickle {
381    ...
382    bool onTasty() const override {
383        return GrPickle::onTasty()
384            && fFreshDill;
385    }
386    ...
387private:
388    bool fFreshDill;
389};
390```
391
392Constructor initializers should be placed on the same line as the constructor,
393if they fit. Otherwise, each initializer should be on its own line, indented,
394with punctuation placed before the initializer.
395
396<!--?prettify?-->
397
398```
399GrDillPickle::GrDillPickle() : GrPickle(), fSize(kDefaultPickleSize) {}
400
401GrDillPickle::GrDillPickle(float size, float crunchiness, const PickleOptions* options)
402        : GrPickle(options)
403        , fSize(size)
404        , fCrunchiness(crunchiness) {}
405```
406
407Constructors that take one argument should almost always be explicit, with
408exceptions made only for the (rare) automatic compatibility class.
409
410<!--?prettify?-->
411
412```
413class Foo {
414    explicit Foo(int x);  // Good.
415    Foo(float y);         // Spooky implicit conversion from float to Foo.  No no no!
416    ...
417};
418```
419
420Method calls within method calls should be prefixed with dereference of the
421'this' pointer. For example:
422
423<!--?prettify?-->
424
425```
426this->method();
427```
428
429A common pattern for virtual methods in Skia is to include a public non-virtual
430(or final) method, paired with a private virtual method named "onMethodName".
431This ensures that the base-class method is always invoked and gives it control
432over how the virtual method is used, rather than relying on each subclass to
433call `Parent::onMethodName()`. For example:
434
435<!--?prettify?-->
436
437```
438class SkSandwich {
439public:
440    void assemble() {
441        // All sandwiches must have bread on the top and bottom.
442        this->addIngredient(kBread_Ingredient);
443        this->onAssemble();
444        this->addIngredient(kBread_Ingredient);
445    }
446    bool cook() {
447        return this->onCook();
448    }
449
450private:
451    // All sandwiches must implement onAssemble.
452    virtual void onAssemble() = 0;
453    // Sandwiches can remain uncooked by default.
454    virtual bool onCook() { return true; }
455};
456
457class SkGrilledCheese : public SkSandwich {
458private:
459    void onAssemble() override {
460        this->addIngredient(kCheese_Ingredient);
461    }
462    bool onCook() override {
463        return this->toastOnGriddle();
464    }
465};
466
467class SkPeanutButterAndJelly : public SkSandwich {
468private:
469    void onAssemble() override {
470        this->addIngredient(kPeanutButter_Ingredient);
471        this->addIngredient(kGrapeJelly_Ingredient);
472    }
473};
474```
475
476## Integer Types
477
478We follow the Google C++ guide for ints and are slowly making older code conform
479to this
480
481(https://google.github.io/styleguide/cppguide.html#Integer_Types)
482
483Summary: Use `int` unless you have need a guarantee on the bit count, then use
484`stdint.h` types (`int32_t`, etc). Assert that counts, etc are not negative
485instead of using unsigned. Bitfields use `uint32_t` unless they have to be made
486shorter for packing or performance reasons.
487
488## Function Parameters
489
490Mandatory constant object parameters are passed to functions as const
491references. Optional constant object parameters are passed to functions as const
492pointers. Mutable object parameters are passed to functions as pointers. We very
493rarely pass anything by non-const reference.
494
495<!--?prettify?-->
496
497```
498// src and paint are optional
499void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
500                              const SkRect& dst, const SkPaint* paint = nullptr);
501
502// metrics is mutable (it is changed by the method)
503SkScalar SkPaint::getFontMetrics(FontMetric* metrics, SkScalar scale) const;
504
505```
506
507If function arguments or parameters do not all fit on one line, the overflowing
508parameters may be lined up with the first parameter on the next line
509
510<!--?prettify?-->
511
512```
513void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst,
514                    const SkPaint* paint = nullptr) {
515    this->drawBitmapRectToRect(bitmap, nullptr, dst, paint,
516                               kNone_DrawBitmapRectFlag);
517}
518```
519
520or all parameters placed on the next line and indented eight spaces
521
522<!--?prettify?-->
523
524```
525void drawBitmapRect(
526        const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint = nullptr) {
527    this->drawBitmapRectToRect(
528            bitmap, nullptr, dst, paint, kNone_DrawBitmapRectFlag);
529}
530```
531
532## Python
533
534Python code follows the
535[Google Python Style Guide](https://google.github.io/styleguide/pyguide.html).
536
537## Folder Organiziation
538
539Skia's public API should live in the `include` directory. Skia's private headers and implementation
540files should live in the `src` directory. The `modules` directory contains extra features that are
541built on top of Skia (`modules/skcms` being an exception) and can be used by clients.
542Private utilities to test Skia live in `tools` and can be used for reference but should not be used
543by clients.
544
545No header in `include` should depend on files in other directories (`modules/skcms` being an exception).
546This is to prevent private symbols from leaking into client code via transitive dependencies.
547