xref: /third_party/skia/site/docs/dev/contrib/style.md (revision cb93a386)
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, we usually privately alias that parent type to
374`INHERITED` within the class. That lets calls like `INHERITED::onFoo()` stand
375out visually. No need for `this->` when using `INHERITED::`.
376
377<!--?prettify?-->
378
379```
380class GrDillPickle : public GrPickle {
381    ...
382    bool onTasty() const override {
383        return INHERITED::onTasty()
384            && fFreshDill;
385    }
386    ...
387private:
388    bool fFreshDill;
389    using INHERITED = GrPickle;
390};
391```
392
393Constructor initializers should be one per line, indented, with punctuation
394placed before the initializer.
395
396<!--?prettify?-->
397
398```
399GrDillPickle::GrDillPickle()
400    : GrPickle()
401    , fSize(kDefaultPickleSize) {
402    ...
403}
404```
405
406Constructors that take one argument should almost always be explicit, with
407exceptions made only for the (rare) automatic compatibility class.
408
409<!--?prettify?-->
410
411```
412class Foo {
413    explicit Foo(int x);  // Good.
414    Foo(float y);         // Spooky implicit conversion from float to Foo.  No no no!
415    ...
416};
417```
418
419Method calls within method calls should be prefixed with dereference of the
420'this' pointer. For example:
421
422<!--?prettify?-->
423
424```
425this->method();
426```
427
428A common pattern for virtual methods in Skia is to include a public non-virtual
429(or final) method, paired with a private virtual method named "onMethodName".
430This ensures that the base-class method is always invoked and gives it control
431over how the virtual method is used, rather than relying on each subclass to
432call `INHERITED::onMethodName`. For example:
433
434<!--?prettify?-->
435
436```
437class SkSandwich {
438public:
439    void assemble() {
440        // All sandwiches must have bread on the top and bottom.
441        this->addIngredient(kBread_Ingredient);
442        this->onAssemble();
443        this->addIngredient(kBread_Ingredient);
444    }
445    bool cook() {
446        return this->onCook();
447    }
448
449private:
450    // All sandwiches must implement onAssemble.
451    virtual void onAssemble() = 0;
452    // Sandwiches can remain uncooked by default.
453    virtual bool onCook() { return true; }
454};
455
456class SkGrilledCheese : public SkSandwich {
457private:
458    void onAssemble() override {
459        this->addIngredient(kCheese_Ingredient);
460    }
461    bool onCook() override {
462        return this->toastOnGriddle();
463    }
464};
465
466class SkPeanutButterAndJelly : public SkSandwich {
467private:
468    void onAssemble() override {
469        this->addIngredient(kPeanutButter_Ingredient);
470        this->addIngredient(kGrapeJelly_Ingredient);
471    }
472};
473```
474
475## Integer Types
476
477We follow the Google C++ guide for ints and are slowly making older code conform
478to this
479
480(https://google.github.io/styleguide/cppguide.html#Integer_Types)
481
482Summary: Use `int` unless you have need a guarantee on the bit count, then use
483`stdint.h` types (`int32_t`, etc). Assert that counts, etc are not negative
484instead of using unsigned. Bitfields use `uint32_t` unless they have to be made
485shorter for packing or performance reasons.
486
487## Function Parameters
488
489Mandatory constant object parameters are passed to functions as const
490references. Optional constant object parameters are passed to functions as const
491pointers. Mutable object parameters are passed to functions as pointers. We very
492rarely pass anything by non-const reference.
493
494<!--?prettify?-->
495
496```
497// src and paint are optional
498void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
499                              const SkRect& dst, const SkPaint* paint = nullptr);
500
501// metrics is mutable (it is changed by the method)
502SkScalar SkPaint::getFontMetrics(FontMetric* metrics, SkScalar scale) const;
503
504```
505
506If function arguments or parameters do not all fit on one line, the overflowing
507parameters may be lined up with the first parameter on the next line
508
509<!--?prettify?-->
510
511```
512void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst,
513                    const SkPaint* paint = nullptr) {
514    this->drawBitmapRectToRect(bitmap, nullptr, dst, paint,
515                               kNone_DrawBitmapRectFlag);
516}
517```
518
519or all parameters placed on the next line and indented eight spaces
520
521<!--?prettify?-->
522
523```
524void drawBitmapRect(
525        const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint = nullptr) {
526    this->drawBitmapRectToRect(
527            bitmap, nullptr, dst, paint, kNone_DrawBitmapRectFlag);
528}
529```
530
531## Python
532
533Python code follows the
534[Google Python Style Guide](https://google.github.io/styleguide/pyguide.html).
535