work on path

Work on SkPath.h documentation; fixed self-consistency
bugs identified by bookmaker. Fixed a couple of
minor typos in SkPath.h itself.

Also brought SkPaint and SkCanvas docs up to date.

TBR=reed@google.com
Docs-Preview: https://skia.org/?cl=39040
Bug: skia: 6898
Change-Id: Id89d4e2fa7fb6ee2e3cbec7ea762e06308b67d8b
Reviewed-on: https://skia-review.googlesource.com/39040
Commit-Queue: Cary Clark <caryclark@skia.org>
Reviewed-by: Cary Clark <caryclark@google.com>
Reviewed-by: Cary Clark <caryclark@skia.org>
This commit is contained in:
Cary Clark 2017-08-29 17:36:51 -04:00 committed by Skia Commit-Bot
parent 1a763632d2
commit 73fa972d0b
12 changed files with 6343 additions and 5923 deletions

View File

@ -67,7 +67,7 @@ when no Surface is required, and some helpers implicitly create Raster_Surface.
# # description ##
#Legend ##
# SkCanvas() # No Surface, no dimensions. ##
# SkCanvas(int width, int height, const SkSurfaceProps* props = NULL) # No Surface, set dimensions, Surface_Properties. ##
# SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr) # No Surface, set dimensions, Surface_Properties. ##
# SkCanvas(SkBaseDevice* device) # Existing Device. (SkBaseDevice is private.) ##
# SkCanvas(const SkBitmap& bitmap) # Uses existing Bitmap. ##
# SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props) # Uses existing Bitmap and Surface_Properties. ##
@ -364,7 +364,7 @@ void draw(SkCanvas* canvas) {
# ------------------------------------------------------------------------------
#Method SkCanvas(int width, int height, const SkSurfaceProps* props = NULL)
#Method SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr)
Creates Canvas of the specified dimensions without a Surface.
Used by subclasses with custom implementations for draw methods.
@ -465,16 +465,16 @@ The actual output depends on the installed fonts.
}
#StdOut
-----
--x--
--x--
--x--
--x--
--x--
--x--
-----
--x--
--x--
-----
---x-
---x-
---x-
---x-
---x-
---x-
-----
---x-
---x-
-----
#StdOut ##
##
@ -803,7 +803,7 @@ void draw(SkCanvas* canvas) {
# ------------------------------------------------------------------------------
#Method void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = NULL)
#Method void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = nullptr)
Returns the pixel base address, Image_Info, rowBytes, and origin if the pixels
can be read directly. The returned address is only valid
@ -3774,7 +3774,7 @@ void draw(SkCanvas* canvas) {
drawImage, drawImageRect, and drawImageNine can be called with a bare pointer or
a smart pointer as a convenience. The pairs of calls are otherwise identical.
#Method void drawImage(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint = NULL)
#Method void drawImage(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint = nullptr)
Draw Image image, with its top-left corner at (left, top),
using Clip, Matrix, and optional Paint paint.
@ -3814,7 +3814,7 @@ void draw(SkCanvas* canvas) {
# ------------------------------------------------------------------------------
#Method void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top,
const SkPaint* paint = NULL)
const SkPaint* paint = nullptr)
Draw Image image, with its top-left corner at (left, top),
using Clip, Matrix, and optional Paint paint.
@ -4362,7 +4362,7 @@ void draw(SkCanvas* canvas) {
# ------------------------------------------------------------------------------
#Method void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
const SkPaint* paint = NULL)
const SkPaint* paint = nullptr)
Draw Bitmap bitmap, with its top-left corner at (left, top),
using Clip, Matrix, and optional Paint paint.
@ -4580,7 +4580,7 @@ void draw(SkCanvas* canvas) {
# ------------------------------------------------------------------------------
#Method void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
const SkPaint* paint = NULL)
const SkPaint* paint = nullptr)
Draw Bitmap bitmap stretched differentially to fit into Rect dst.
IRect center divides the bitmap into nine sections: four sides, four corners,
@ -5843,7 +5843,7 @@ void draw(SkCanvas* canvas) {
# ------------------------------------------------------------------------------
#Method void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = NULL)
#Method void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr)
Draw Drawable drawable using Clip and Matrix, concatenated with
optional matrix.

View File

@ -4713,7 +4713,7 @@ text contains an invalid UTF-8 sequence, zero is returned.
##
#Method size_t breakText(const void* text, size_t length, SkScalar maxWidth,
SkScalar* measuredWidth = NULL) const
SkScalar* measuredWidth = nullptr) const
Returns the bytes of text that fit within maxWidth.
If kVerticalText_Flag is clear, the text fragment fits if its advance width is less than or
@ -4757,7 +4757,7 @@ text contains an invalid UTF-8 sequence, zero is returned.
##
#Method int getTextWidths(const void* text, size_t byteLength, SkScalar widths[],
SkRect bounds[] = NULL) const
SkRect bounds[] = nullptr) const
Retrieves the advance and bounds for each glyph in text, and returns
the glyph count in text.

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,8 @@
GPU GPU-backed OpenGL Vulkan
NULL
RFC
Bezier Coons
Bezier Coons Cartesian
C C++
SaveLayerFlags # not external; need to add typedef support
SkUserConfig.h # not external, but still thinking about how markup refers to this
SkXXX.h # ditto

View File

@ -83,7 +83,7 @@ public:
kInverseWinding_FillType,
/** Same as EvenOdd, but draws outside of the path, rather than inside
*/
kInverseEvenOdd_FillType
kInverseEvenOdd_FillType,
};
/** Return the path's fill type. This is used to define how "inside" is
@ -116,7 +116,7 @@ public:
enum Convexity {
kUnknown_Convexity,
kConvex_Convexity,
kConcave_Convexity
kConcave_Convexity,
};
/**
@ -848,7 +848,7 @@ public:
Instead, the start of source path will be extended by a straight
line to the end point of the destination path.
*/
kExtend_AddPathMode
kExtend_AddPathMode,
};
/** Add a copy of src to the path, offset by (dx,dy)
@ -973,9 +973,9 @@ public:
class SK_API Iter {
public:
Iter();
Iter(const SkPath&, bool forceClose);
Iter(const SkPath& path, bool forceClose);
void setPath(const SkPath&, bool forceClose);
void setPath(const SkPath& path, bool forceClose);
/** Return the next verb in this iteration of the path. When all
segments have been visited, return kDone_Verb.
@ -989,8 +989,8 @@ public:
doConsumeDegenerates is false, exact has no effect.
@return The verb for the current segment
*/
Verb next(SkPoint pts[4], bool doConsumeDegerates = true, bool exact = false) {
if (doConsumeDegerates) {
Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false) {
if (doConsumeDegenerates) {
this->consumeDegenerateSegments(exact);
}
return this->doNext(pts);

View File

@ -56,9 +56,9 @@ when no <a href="undocumented#Surface">Surface</a> is required, and some helpers
| | description |
| --- | --- |
| <a href="#SkCanvas_empty_constructor">SkCanvas()</a> | No <a href="undocumented#Surface">Surface</a>, no dimensions. |
| <a href="#SkCanvas_int_int_const_SkSurfaceProps_star">SkCanvas(int width, int height, const SkSurfaceProps* props = NULL)</a> | No <a href="undocumented#Surface">Surface</a>, set dimensions, <a href="#Properties">Surface Properties</a>. |
| <a href="#SkCanvas_copy_constructor">SkCanvas(SkBaseDevice* device)</a> | Existing <a href="undocumented#Device">Device</a>. (<a href="undocumented#SkBaseDevice">SkBaseDevice</a> is private.) |
| <a href="#SkCanvas_copy_constructor">SkCanvas(const SkBitmap& bitmap)</a> | Uses existing <a href="undocumented#Bitmap">Bitmap</a>. |
| <a href="#SkCanvas_int_int_const_SkSurfaceProps_star">SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr)</a> | No <a href="undocumented#Surface">Surface</a>, set dimensions, <a href="#Properties">Surface Properties</a>. |
| <a href="#SkCanvas_copy_SkBaseDevice_star">SkCanvas(SkBaseDevice* device)</a> | Existing <a href="undocumented#Device">Device</a>. (<a href="undocumented#SkBaseDevice">SkBaseDevice</a> is private.) |
| <a href="#SkCanvas_copy_const_SkBitmap">SkCanvas(const SkBitmap& bitmap)</a> | Uses existing <a href="undocumented#Bitmap">Bitmap</a>. |
| <a href="#SkCanvas_const_SkBitmap_const_SkSurfaceProps">SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)</a> | Uses existing <a href="undocumented#Bitmap">Bitmap</a> and <a href="#Properties">Surface Properties</a>. |
| <a href="#SkCanvas_MakeRasterDirect">MakeRasterDirect</a> | Creates from <a href="undocumented#SkImageInfo">SkImageInfo</a> and <a href="#Storage">Pixel Storage</a>. |
| <a href="#SkCanvas_MakeRasterDirectN32">MakeRasterDirectN32</a> | Creates from image data and <a href="#Storage">Pixel Storage</a>. |
@ -133,7 +133,7 @@ when no <a href="undocumented#Surface">Surface</a> is required, and some helpers
| <a href="#SkCanvas_quickReject">quickReject</a> | Returns if <a href="undocumented#Rect">Rect</a> is outside <a href="#Clip">Clip</a>. |
| <a href="#SkCanvas_readPixels">readPixels</a> | Copies and converts rectangle of pixels from <a href="#Canvas">Canvas</a>. |
| <a href="#SkCanvas_resetMatrix">resetMatrix</a> | Resets <a href="#Matrix">Matrix</a> to identity. |
| <a href="#SkCanvas_restore">restore</a> | Restores changes to <a href="#Clip">Clip</a> and <a href="#Matrix">Matrix</a>, pops save stack. |
| <a href="#SkCanvas_restore">restore</a> | Restores changes to <a href="#Clip">Clip</a> and <a href="#Matrix">Matrix</a>, pops <a href="#SkCanvas_save">save</a> stack. |
| <a href="#SkCanvas_restoreToCount">restoreToCount</a> | Restores changes to <a href="#Clip">Clip</a> and <a href="#Matrix">Matrix</a> to given depth. |
| <a href="#SkCanvas_rotate">rotate</a> | Rotates <a href="#Matrix">Matrix</a>. |
| <a href="#SkCanvas_save">save</a> | Saves <a href="#Clip">Clip</a> and <a href="#Matrix">Matrix</a> on stack. |
@ -305,7 +305,7 @@ paint draws text top to bottom
## SkCanvas
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
SkCanvas(int width, int height, const SkSurfaceProps* props = NULL)
SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr)
</pre>
Creates <a href="#Canvas">Canvas</a> of the specified dimensions without a <a href="undocumented#Surface">Surface</a>.
@ -351,51 +351,51 @@ canvas is empty
---
<a name="SkCanvas_copy_constructor"></a>
<a name="SkCanvas_copy_SkBaseDevice_star"></a>
## SkCanvas
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
explicit SkCanvas(SkBaseDevice* device)
</pre>
Construct a canvas that draws into <a href="#SkCanvas_copy_constructor_device">device</a>.
Construct a canvas that draws into <a href="#SkCanvas_copy_SkBaseDevice_star_device">device</a>.
Used by child classes of <a href="#SkCanvas">SkCanvas</a>.
### Parameters
<table> <tr> <td><a name="SkCanvas_copy_constructor_device"> <code><strong>device </strong></code> </a></td> <td>
specifies a <a href="#SkCanvas_copy_constructor_device">device</a> for the canvas to draw into</td>
<table> <tr> <td><a name="SkCanvas_copy_SkBaseDevice_star_device"> <code><strong>device </strong></code> </a></td> <td>
specifies a <a href="#SkCanvas_copy_SkBaseDevice_star_device">device</a> for the canvas to draw into</td>
</tr>
</table>
### Return Value
<a href="#Canvas">Canvas</a> that can be used to draw into <a href="#SkCanvas_copy_constructor_device">device</a>
<a href="#Canvas">Canvas</a> that can be used to draw into <a href="#SkCanvas_copy_SkBaseDevice_star_device">device</a>
### Example
<div><fiddle-embed name="cc6d6fd6d9aa98b12984e11ef52172ec"></fiddle-embed></div>
<div><fiddle-embed name=""></fiddle-embed></div>
---
<a name="SkCanvas_copy_constructor"></a>
<a name="SkCanvas_copy_const_SkBitmap"></a>
## SkCanvas
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
explicit SkCanvas(const SkBitmap& bitmap)
</pre>
Construct a canvas that draws into <a href="#SkCanvas_copy_constructor_bitmap">bitmap</a>.
Construct a canvas that draws into <a href="#SkCanvas_copy_const_SkBitmap_bitmap">bitmap</a>.
Sets <a href="#SkSurfaceProps_kLegacyFontHost_InitType">SkSurfaceProps::kLegacyFontHost InitType</a> in constructed <a href="undocumented#Surface">Surface</a>.
<a href="undocumented#Bitmap">Bitmap</a> is copied so that subsequently editing <a href="#SkCanvas_copy_constructor_bitmap">bitmap</a> will not affect
<a href="undocumented#Bitmap">Bitmap</a> is copied so that subsequently editing <a href="#SkCanvas_copy_const_SkBitmap_bitmap">bitmap</a> will not affect
constructed <a href="#Canvas">Canvas</a>.
May be deprecated in the future.
### Parameters
<table> <tr> <td><a name="SkCanvas_copy_constructor_bitmap"> <code><strong>bitmap </strong></code> </a></td> <td>
<table> <tr> <td><a name="SkCanvas_copy_const_SkBitmap_bitmap"> <code><strong>bitmap </strong></code> </a></td> <td>
width, height, <a href="#Color_Type">Image Color Type</a>, <a href="#Alpha_Type">Image Alpha Type</a>, and pixel
storage of <a href="undocumented#Raster_Surface">Raster Surface</a></td>
</tr>
@ -403,25 +403,25 @@ storage of <a href="undocumented#Raster_Surface">Raster Surface</a></td>
### Return Value
<a href="#Canvas">Canvas</a> that can be used to draw into <a href="#SkCanvas_copy_constructor_bitmap">bitmap</a>
<a href="#Canvas">Canvas</a> that can be used to draw into <a href="#SkCanvas_copy_const_SkBitmap_bitmap">bitmap</a>
### Example
<div><fiddle-embed name=""><div>The actual output depends on the installed fonts.</div>
<div><fiddle-embed name="cc6d6fd6d9aa98b12984e11ef52172ec"><div>The actual output depends on the installed fonts.</div>
#### Example Output
~~~~
-----
--x--
--x--
--x--
--x--
--x--
--x--
---x-
---x-
---x-
---x-
---x-
---x-
-----
--x--
--x--
---x-
---x-
-----
~~~~
@ -749,7 +749,7 @@ Returns <a href="undocumented#GPU_Context">GPU Context</a> of the <a href="undoc
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes,
SkIPoint* origin = NULL)
SkIPoint* origin = nullptr)
</pre>
Returns the pixel base address, <a href="#Info">Image Info</a>, <a href="#SkCanvas_accessTopLayerPixels_rowBytes">rowBytes</a>, and <a href="#SkCanvas_accessTopLayerPixels_origin">origin</a> if the pixels
@ -1227,13 +1227,13 @@ bounds of the <a href="#Canvas">Canvas</a> <a href="undocumented#Surface">Surfac
<a href="undocumented#Draw_Filter">Draw Filter</a> (deprecated on most platforms) modifies the paint before drawing.
<a href="#SkCanvas_save">save</a>, <a href="#SkCanvas_saveLayer">saveLayer</a>, <a href="#SkCanvas_saveLayerPreserveLCDTextRequests">saveLayerPreserveLCDTextRequests</a>, and <a href="#SkCanvas_saveLayerAlpha">saveLayerAlpha</a>
save state and return the depth of the stack.
<a href="#SkCanvas_save">save</a> state and return the depth of the stack.
<a href="#SkCanvas_restore">restore</a>, <a href="#SkCanvas_restoreToCount">restoreToCount</a>, and
### Example
<div><fiddle-embed name="a4548baa133302e933b4d3442c06f5b3"><div>Draw to ever smaller clips; then restore drawing to full canvas.
<div><fiddle-embed name="a4548baa133302e933b4d3442c06f5b3"><div>Draw to ever smaller clips; then <a href="#SkCanvas_restore">restore</a> drawing to full canvas.
Note that the second <a href="#SkCanvas_clipRect">clipRect</a> is not permitted to enlarge <a href="#Clip">Clip</a>.</div></fiddle-embed></div>
Each <a href="#Clip">Clip</a> uses the current <a href="#Matrix">Matrix</a> for its coordinates.
@ -1264,7 +1264,7 @@ and <a href="#SkCanvas_resetMatrix">resetMatrix</a>. <a href="#Clip">Clip</a> ma
Saved <a href="#Canvas">Canvas</a> state is put on a stack; multiple calls to <a href="#SkCanvas_save">save</a> should be balance
by an equal number of calls to <a href="#SkCanvas_restore">restore</a>.
Call <a href="#SkCanvas_restoreToCount">restoreToCount</a> with result to restore this and subsequent saves.
Call <a href="#SkCanvas_restoreToCount">restoreToCount</a> with result to <a href="#SkCanvas_restore">restore</a> this and subsequent saves.
### Return Value
@ -1312,7 +1312,7 @@ a specific rectangle, use <a href="#SkCanvas_clipRect">clipRect</a>.
Optional <a href="SkPaint_Reference#Paint">Paint</a> <a href="#SkCanvas_saveLayer_paint">paint</a> applies <a href="#Alpha">Color Alpha</a>, <a href="undocumented#Color_Filter">Color Filter</a>, <a href="undocumented#Image_Filter">Image Filter</a>, and
<a href="undocumented#Blend_Mode">Blend Mode</a> when <a href="#SkCanvas_restore">restore</a> is called.
Call <a href="#SkCanvas_restoreToCount">restoreToCount</a> with returned value to restore this and subsequent saves.
Call <a href="#SkCanvas_restoreToCount">restoreToCount</a> with returned value to <a href="#SkCanvas_restore">restore</a> this and subsequent saves.
### Parameters
@ -1353,7 +1353,7 @@ a specific rectangle, use <a href="#SkCanvas_clipRect">clipRect</a>.
Optional <a href="SkPaint_Reference#Paint">Paint</a> <a href="#SkCanvas_saveLayer_2_paint">paint</a> applies <a href="#Alpha">Color Alpha</a>, <a href="undocumented#Color_Filter">Color Filter</a>, <a href="undocumented#Image_Filter">Image Filter</a>, and
<a href="undocumented#Blend_Mode">Blend Mode</a> when <a href="#SkCanvas_restore">restore</a> is called.
Call <a href="#SkCanvas_restoreToCount">restoreToCount</a> with returned value to restore this and subsequent saves.
Call <a href="#SkCanvas_restoreToCount">restoreToCount</a> with returned value to <a href="#SkCanvas_restore">restore</a> this and subsequent saves.
### Parameters
@ -1399,7 +1399,7 @@ a specific rectangle, use <a href="#SkCanvas_clipRect">clipRect</a>.
Optional <a href="SkPaint_Reference#Paint">Paint</a> <a href="#SkCanvas_saveLayerPreserveLCDTextRequests_paint">paint</a> applies <a href="#Alpha">Color Alpha</a>, <a href="undocumented#Color_Filter">Color Filter</a>, <a href="undocumented#Image_Filter">Image Filter</a>, and
<a href="undocumented#Blend_Mode">Blend Mode</a> when <a href="#SkCanvas_restore">restore</a> is called.
Call <a href="#SkCanvas_restoreToCount">restoreToCount</a> with returned value to restore this and subsequent saves.
Call <a href="#SkCanvas_restoreToCount">restoreToCount</a> with returned value to <a href="#SkCanvas_restore">restore</a> this and subsequent saves.
Draw text on an opaque background so that <a href="SkPaint_Reference#LCD_Text">LCD Text</a> blends correctly with the
prior layer. <a href="SkPaint_Reference#LCD_Text">LCD Text</a> drawn on a background with transparency may result in
@ -1446,7 +1446,7 @@ a specific rectangle, use <a href="#SkCanvas_clipRect">clipRect</a>.
<a href="#SkCanvas_saveLayerAlpha_alpha">alpha</a> of zero is fully transparent, 255 is fully opaque.
Call <a href="#SkCanvas_restoreToCount">restoreToCount</a> with returned value to restore this and subsequent saves.
Call <a href="#SkCanvas_restoreToCount">restoreToCount</a> with returned value to <a href="#SkCanvas_restore">restore</a> this and subsequent saves.
### Parameters
@ -1721,7 +1721,7 @@ and blends the offscreen bitmap with alpha opacity onto the prior layer.
<a href="#SkCanvas_SaveLayerRec">SaveLayerRec</a> contains the state used to create the layer offscreen.
Call <a href="#SkCanvas_restoreToCount">restoreToCount</a> with returned value to restore this and subsequent saves.
Call <a href="#SkCanvas_restoreToCount">restoreToCount</a> with returned value to <a href="#SkCanvas_restore">restore</a> this and subsequent saves.
### Parameters
@ -1732,12 +1732,12 @@ offscreen state</td>
### Return Value
depth of save state stack
depth of <a href="#SkCanvas_save">save</a> state stack
### Example
<div><fiddle-embed name="0da8c199f1d9ec4d1b9c5d1114d6cbd6"><div>The example draws an image, and saves it into a layer with <a href="#SkCanvas_kInitWithPrevious_SaveLayerFlag">kInitWithPrevious SaveLayerFlag</a>.
Next it punches a hole in the layer and restore with <a href="#SkBlendMode_kPlus">SkBlendMode::kPlus</a>.
Next it punches a hole in the layer and <a href="#SkCanvas_restore">restore</a> with <a href="#SkBlendMode_kPlus">SkBlendMode::kPlus</a>.
Where the layer was cleared, the original image will draw unchanged.
Outside of the circle the mandrill is brightened.</div></fiddle-embed></div>
@ -1770,11 +1770,11 @@ int getSaveCount() const
Returns the number of saved states, each containing: <a href="#Matrix">Matrix</a>, <a href="#Clip">Clip</a>, and <a href="undocumented#Draw_Filter">Draw Filter</a>.
Equals the number of <a href="#SkCanvas_save">save</a> calls less the number of <a href="#SkCanvas_restore">restore</a> calls plus one.
The save count of a new canvas is one.
The <a href="#SkCanvas_save">save</a> count of a new canvas is one.
### Return Value
depth of save state stack
depth of <a href="#SkCanvas_save">save</a> state stack
### Example
@ -1808,7 +1808,7 @@ Restores state to initial values if <a href="#SkCanvas_restoreToCount_saveCount"
### Parameters
<table> <tr> <td><a name="SkCanvas_restoreToCount_saveCount"> <code><strong>saveCount </strong></code> </a></td> <td>
depth of state stack to restore</td>
depth of state stack to <a href="#SkCanvas_restore">restore</a></td>
</tr>
</table>
@ -1848,9 +1848,9 @@ the result with <a href="#Matrix">Matrix</a>.
### Parameters
<table> <tr> <td><a name="SkCanvas_translate_dx"> <code><strong>dx </strong></code> </a></td> <td>
distance to translate in x</td>
distance to <a href="#SkCanvas_translate">translate</a> in x</td>
</tr> <tr> <td><a name="SkCanvas_translate_dy"> <code><strong>dy </strong></code> </a></td> <td>
distance to translate in y</td>
distance to <a href="#SkCanvas_translate">translate</a> in y</td>
</tr>
</table>
@ -1859,10 +1859,10 @@ distance to translate in y</td>
<div><fiddle-embed name="eb93d5fa66a5f7a10f4f9210494d7222"><div><a href="#SkCanvas_scale">scale</a> followed by <a href="#SkCanvas_translate">translate</a> produces different results from <a href="#SkCanvas_translate">translate</a> followed
by <a href="#SkCanvas_scale">scale</a>.
The blue stroke follows translate of (50, 50); a black
fill follows scale of (2, 1/2.f). After restoring the clip, which resets
<a href="#Matrix">Matrix</a>, a red frame follows the same scale of (2, 1/2.f); a gray fill
follows translate of (50, 50).</div></fiddle-embed></div>
The blue stroke follows <a href="#SkCanvas_translate">translate</a> of (50, 50); a black
fill follows <a href="#SkCanvas_scale">scale</a> of (2, 1/2.f). After restoring the clip, which resets
<a href="#Matrix">Matrix</a>, a red frame follows the same <a href="#SkCanvas_scale">scale</a> of (2, 1/2.f); a gray fill
follows <a href="#SkCanvas_translate">translate</a> of (50, 50).</div></fiddle-embed></div>
---
@ -1875,7 +1875,7 @@ void scale(SkScalar sx, SkScalar sy)
Scale <a href="#Matrix">Matrix</a> by <a href="#SkCanvas_scale_sx">sx</a> on the x-axis and <a href="#SkCanvas_scale_sy">sy</a> on the y-axis.
Mathematically, replace <a href="#Matrix">Matrix</a> with a scale matrix
Mathematically, replace <a href="#Matrix">Matrix</a> with a <a href="#SkCanvas_scale">scale</a> matrix
pre-multiplied with <a href="#Matrix">Matrix</a>.
This has the effect of scaling the drawing by (<a href="#SkCanvas_scale_sx">sx</a>, <a href="#SkCanvas_scale_sy">sy</a>) before transforming
@ -1884,9 +1884,9 @@ the result with <a href="#Matrix">Matrix</a>.
### Parameters
<table> <tr> <td><a name="SkCanvas_scale_sx"> <code><strong>sx </strong></code> </a></td> <td>
amount to scale in x</td>
amount to <a href="#SkCanvas_scale">scale</a> in x</td>
</tr> <tr> <td><a name="SkCanvas_scale_sy"> <code><strong>sy </strong></code> </a></td> <td>
amount to scale in y</td>
amount to <a href="#SkCanvas_scale">scale</a> in y</td>
</tr>
</table>
@ -1914,7 +1914,7 @@ the result with <a href="#Matrix">Matrix</a>.
### Parameters
<table> <tr> <td><a name="SkCanvas_rotate_degrees"> <code><strong>degrees </strong></code> </a></td> <td>
amount to rotate, in <a href="#SkCanvas_rotate_degrees">degrees</a></td>
amount to <a href="#SkCanvas_rotate">rotate</a>, in <a href="#SkCanvas_rotate_degrees">degrees</a></td>
</tr>
</table>
@ -1942,11 +1942,11 @@ transforming the result with <a href="#Matrix">Matrix</a>.
### Parameters
<table> <tr> <td><a name="SkCanvas_rotate_2_degrees"> <code><strong>degrees </strong></code> </a></td> <td>
amount to rotate, in <a href="#SkCanvas_rotate_2_degrees">degrees</a></td>
amount to <a href="#SkCanvas_rotate">rotate</a>, in <a href="#SkCanvas_rotate_2_degrees">degrees</a></td>
</tr> <tr> <td><a name="SkCanvas_rotate_2_px"> <code><strong>px </strong></code> </a></td> <td>
x-coordinate of the point to rotate about</td>
x-coordinate of the point to <a href="#SkCanvas_rotate">rotate</a> about</td>
</tr> <tr> <td><a name="SkCanvas_rotate_2_py"> <code><strong>py </strong></code> </a></td> <td>
y-coordinate of the point to rotate about</td>
y-coordinate of the point to <a href="#SkCanvas_rotate">rotate</a> about</td>
</tr>
</table>
@ -1967,7 +1967,7 @@ Skew <a href="#Matrix">Matrix</a> by <a href="#SkCanvas_skew_sx">sx</a> on the x
skews the drawing right as y increases; a positive value of <a href="#SkCanvas_skew_sy">sy</a> skews the drawing
down as x increases.
Mathematically, replace <a href="#Matrix">Matrix</a> with a skew matrix pre-multiplied with <a href="#Matrix">Matrix</a>.
Mathematically, replace <a href="#Matrix">Matrix</a> with a <a href="#SkCanvas_skew">skew</a> matrix pre-multiplied with <a href="#Matrix">Matrix</a>.
This has the effect of skewing the drawing by (<a href="#SkCanvas_skew_sx">sx</a>, <a href="#SkCanvas_skew_sy">sy</a>) before transforming
the result with <a href="#Matrix">Matrix</a>.
@ -1975,19 +1975,19 @@ the result with <a href="#Matrix">Matrix</a>.
### Parameters
<table> <tr> <td><a name="SkCanvas_skew_sx"> <code><strong>sx </strong></code> </a></td> <td>
amount to skew in x</td>
amount to <a href="#SkCanvas_skew">skew</a> in x</td>
</tr> <tr> <td><a name="SkCanvas_skew_sy"> <code><strong>sy </strong></code> </a></td> <td>
amount to skew in y</td>
amount to <a href="#SkCanvas_skew">skew</a> in y</td>
</tr>
</table>
### Example
<div><fiddle-embed name="2e2acc21d7774df7e0940a30ad2ca99e"><div>Black text mimics an oblique text style by using a negative skew in x that
<div><fiddle-embed name="2e2acc21d7774df7e0940a30ad2ca99e"><div>Black text mimics an oblique text style by using a negative <a href="#SkCanvas_skew">skew</a> in x that
shifts the geometry to the right as the y values decrease.
Red text uses a positive skew in y to shift the geometry down as the x values
Red text uses a positive <a href="#SkCanvas_skew">skew</a> in y to shift the geometry down as the x values
increase.
Blue text combines x and y skew to rotate and scale.</div></fiddle-embed></div>
Blue text combines x and y <a href="#SkCanvas_skew">skew</a> to <a href="#SkCanvas_rotate">rotate</a> and <a href="#SkCanvas_scale">scale</a>.</div></fiddle-embed></div>
---
@ -3320,7 +3320,7 @@ a smart pointer as a convenience. The pairs of calls are otherwise identical.
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
void drawImage(const SkImage* image, SkScalar left, SkScalar top,
const SkPaint* paint = NULL)
const SkPaint* paint = nullptr)
</pre>
Draw <a href="undocumented#Image">Image</a> <a href="#SkCanvas_drawImage_image">image</a>, with its top-left corner at (<a href="#SkCanvas_drawImage_left">left</a>, <a href="#SkCanvas_drawImage_top">top</a>),
@ -3355,7 +3355,7 @@ and so on; or nullptr</td>
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top,
const SkPaint* paint = NULL)
const SkPaint* paint = nullptr)
</pre>
Draw <a href="undocumented#Image">Image</a> <a href="#SkCanvas_drawImage_2_image">image</a>, with its top-left corner at (<a href="#SkCanvas_drawImage_2_left">left</a>, <a href="#SkCanvas_drawImage_2_top">top</a>),
@ -3787,7 +3787,7 @@ and below <a href="#SkCanvas_drawImageNine_2_center">center</a> to fill the rema
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
const SkPaint* paint = NULL)
const SkPaint* paint = nullptr)
</pre>
Draw <a href="undocumented#Bitmap">Bitmap</a> <a href="#SkCanvas_drawBitmap_bitmap">bitmap</a>, with its top-left corner at (<a href="#SkCanvas_drawBitmap_left">left</a>, <a href="#SkCanvas_drawBitmap_top">top</a>),
@ -3962,7 +3962,7 @@ filter strictly within src or draw faster</td>
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
const SkRect& dst, const SkPaint* paint = NULL)
const SkRect& dst, const SkPaint* paint = nullptr)
</pre>
Draw <a href="undocumented#Bitmap">Bitmap</a> <a href="#SkCanvas_drawBitmapNine_bitmap">bitmap</a> stretched differentially to fit into <a href="undocumented#Rect">Rect</a> <a href="#SkCanvas_drawBitmapNine_dst">dst</a>.
@ -4096,9 +4096,9 @@ Draw <a href="undocumented#Bitmap">Bitmap</a> <a href="#SkCanvas_drawBitmapLatti
<a href="#SkCanvas_Lattice">Lattice</a> <a href="#SkCanvas_drawBitmapLattice_lattice">lattice</a> divides <a href="#SkCanvas_drawBitmapLattice_bitmap">bitmap</a> into a rectangular grid.
Each intersection of an even-numbered row and column is fixed; like the corners
of <a href="#SkCanvas_drawBitmapNine">drawBitmapNine</a>, fixed <a href="#SkCanvas_drawBitmapLattice_lattice">lattice</a> elements never scale larger than their initial
of <a href="#SkCanvas_drawBitmapNine">drawBitmapNine</a>, fixed <a href="#SkCanvas_drawBitmapLattice_lattice">lattice</a> elements never <a href="#SkCanvas_scale">scale</a> larger than their initial
size and shrink proportionately when all fixed elements exceed the <a href="#SkCanvas_drawBitmapLattice_bitmap">bitmap</a>'s
dimension. All other grid elements scale to fill the available space, if any.
dimension. All other grid elements <a href="#SkCanvas_scale">scale</a> to fill the available space, if any.
Additionally transform draw using <a href="#Clip">Clip</a>, <a href="#Matrix">Matrix</a>, and optional <a href="SkPaint_Reference#Paint">Paint</a> <a href="#SkCanvas_drawBitmapLattice_paint">paint</a>.
@ -4148,9 +4148,9 @@ Draw <a href="undocumented#Image">Image</a> <a href="#SkCanvas_drawImageLattice_
<a href="#SkCanvas_Lattice">Lattice</a> <a href="#SkCanvas_drawImageLattice_lattice">lattice</a> divides <a href="#SkCanvas_drawImageLattice_image">image</a> into a rectangular grid.
Each intersection of an even-numbered row and column is fixed; like the corners
of <a href="#SkCanvas_drawBitmapNine">drawBitmapNine</a>, fixed <a href="#SkCanvas_drawImageLattice_lattice">lattice</a> elements never scale larger than their initial
of <a href="#SkCanvas_drawBitmapNine">drawBitmapNine</a>, fixed <a href="#SkCanvas_drawImageLattice_lattice">lattice</a> elements never <a href="#SkCanvas_scale">scale</a> larger than their initial
size and shrink proportionately when all fixed elements exceed the bitmap's
dimension. All other grid elements scale to fill the available space, if any.
dimension. All other grid elements <a href="#SkCanvas_scale">scale</a> to fill the available space, if any.
Additionally transform draw using <a href="#Clip">Clip</a>, <a href="#Matrix">Matrix</a>, and optional <a href="SkPaint_Reference#Paint">Paint</a> <a href="#SkCanvas_drawImageLattice_paint">paint</a>.
@ -4517,7 +4517,7 @@ void drawTextRSXform(const void* text, size_t byteLength,
Draw <a href="#SkCanvas_drawTextRSXform_text">text</a>, transforming each glyph by the corresponding <a href="undocumented#SkRSXform">SkRSXform</a>,
using <a href="#Clip">Clip</a>, <a href="#Matrix">Matrix</a>, and <a href="SkPaint_Reference#Paint">Paint</a> <a href="#SkCanvas_drawTextRSXform_paint">paint</a>.
<a href="undocumented#RSXform">RSXform</a> array specifies a separate square scale, rotation, and translation for
<a href="undocumented#RSXform">RSXform</a> array specifies a separate square <a href="#SkCanvas_scale">scale</a>, rotation, and translation for
each glyph.
Optional <a href="undocumented#Rect">Rect</a> <a href="#SkCanvas_drawTextRSXform_cullRect">cullRect</a> is a conservative bounds of <a href="#SkCanvas_drawTextRSXform_text">text</a>, taking into account
@ -4688,7 +4688,7 @@ Draw <a href="undocumented#Picture">Picture</a> <a href="#SkCanvas_drawPicture_3
<table> <tr> <td><a name="SkCanvas_drawPicture_3_picture"> <code><strong>picture </strong></code> </a></td> <td>
recorded drawing commands to play</td>
</tr> <tr> <td><a name="SkCanvas_drawPicture_3_matrix"> <code><strong>matrix </strong></code> </a></td> <td>
<a href="#Matrix">Matrix</a> to rotate, scale, translate, and so on; may be nullptr</td>
<a href="#Matrix">Matrix</a> to <a href="#SkCanvas_rotate">rotate</a>, <a href="#SkCanvas_scale">scale</a>, <a href="#SkCanvas_translate">translate</a>, and so on; may be nullptr</td>
</tr> <tr> <td><a name="SkCanvas_drawPicture_3_paint"> <code><strong>paint </strong></code> </a></td> <td>
<a href="SkPaint_Reference#Paint">Paint</a> to apply transparency, filtering, and so on; may be nullptr</td>
</tr>
@ -4717,7 +4717,7 @@ Draw <a href="undocumented#Picture">Picture</a> <a href="#SkCanvas_drawPicture_4
<table> <tr> <td><a name="SkCanvas_drawPicture_4_picture"> <code><strong>picture </strong></code> </a></td> <td>
recorded drawing commands to play</td>
</tr> <tr> <td><a name="SkCanvas_drawPicture_4_matrix"> <code><strong>matrix </strong></code> </a></td> <td>
<a href="#Matrix">Matrix</a> to rotate, scale, translate, and so on; may be nullptr</td>
<a href="#Matrix">Matrix</a> to <a href="#SkCanvas_rotate">rotate</a>, <a href="#SkCanvas_scale">scale</a>, <a href="#SkCanvas_translate">translate</a>, and so on; may be nullptr</td>
</tr> <tr> <td><a name="SkCanvas_drawPicture_4_paint"> <code><strong>paint </strong></code> </a></td> <td>
<a href="SkPaint_Reference#Paint">Paint</a> to apply transparency, filtering, and so on; may be nullptr</td>
</tr>
@ -5050,7 +5050,7 @@ number of sprites to draw</td>
## drawDrawable
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = NULL)
void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr)
</pre>
Draw <a href="undocumented#Drawable">Drawable</a> <a href="#SkCanvas_drawDrawable_drawable">drawable</a> using <a href="#Clip">Clip</a> and <a href="#Matrix">Matrix</a>, concatenated with

View File

@ -101,8 +101,8 @@ Multiple colors are drawn either by using multiple paints or with objects like
| | description |
| --- | --- |
| <a href="#SkPaint_empty_constructor">SkPaint()</a> | Constructs with default values. |
| <a href="#SkPaint_copy_constructor">SkPaint(const SkPaint& paint)</a> | Makes a shallow copy. |
| <a href="#SkPaint_move_constructor">SkPaint(SkPaint&& paint)</a> | Moves paint without copying it. |
| <a href="#SkPaint_copy_const_SkPaint">SkPaint(const SkPaint& paint)</a> | Makes a shallow copy. |
| <a href="#SkPaint_move_SkPaint">SkPaint(SkPaint&& paint)</a> | Moves paint without copying it. |
| | Decreases <a href="undocumented#Reference_Count">Reference Count</a> of owned objects. |
## <a name="Operators"></a> Operators
@ -283,7 +283,7 @@ default initialized <a href="#Paint">Paint</a>
---
<a name="SkPaint_copy_constructor"></a>
<a name="SkPaint_copy_const_SkPaint"></a>
## SkPaint
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
@ -292,7 +292,7 @@ SkPaint(const SkPaint& paint)
Makes a shallow copy of <a href="#Paint">Paint</a>. <a href="undocumented#Typeface">Typeface</a>, <a href="undocumented#Path_Effect">Path Effect</a>, <a href="undocumented#Shader">Shader</a>,
<a href="undocumented#Mask_Filter">Mask Filter</a>, <a href="undocumented#Color_Filter">Color Filter</a>, <a href="undocumented#Rasterizer">Rasterizer</a>, <a href="undocumented#Draw_Looper">Draw Looper</a>, and <a href="undocumented#Image_Filter">Image Filter</a> are shared
between the original <a href="#SkPaint_copy_constructor_paint">paint</a> and the copy. Objects containing <a href="undocumented#Reference_Count">Reference Count</a> increment
between the original <a href="#SkPaint_copy_const_SkPaint_paint">paint</a> and the copy. Objects containing <a href="undocumented#Reference_Count">Reference Count</a> increment
their references by one.
The referenced objects <a href="undocumented#Path_Effect">Path Effect</a>, <a href="undocumented#Shader">Shader</a>, <a href="undocumented#Mask_Filter">Mask Filter</a>, <a href="undocumented#Color_Filter">Color Filter</a>, <a href="undocumented#Rasterizer">Rasterizer</a>,
@ -301,14 +301,14 @@ This prevents objects with <a href="undocumented#Reference_Count">Reference Coun
### Parameters
<table> <tr> <td><a name="SkPaint_copy_constructor_paint"> <code><strong>paint </strong></code> </a></td> <td>
<table> <tr> <td><a name="SkPaint_copy_const_SkPaint_paint"> <code><strong>paint </strong></code> </a></td> <td>
original to copy</td>
</tr>
</table>
### Return Value
shallow copy of <a href="#SkPaint_copy_constructor_paint">paint</a>
shallow copy of <a href="#SkPaint_copy_const_SkPaint_paint">paint</a>
### Example
@ -325,7 +325,7 @@ SK_ColorBLUE == paint2.getColor()
---
<a name="SkPaint_move_constructor"></a>
<a name="SkPaint_move_SkPaint"></a>
## SkPaint
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
@ -333,20 +333,20 @@ SkPaint(SkPaint&& paint)
</pre>
Implements a move constructor to avoid incrementing the reference counts
of objects referenced by the <a href="#SkPaint_move_constructor_paint">paint</a>.
of objects referenced by the <a href="#SkPaint_move_SkPaint_paint">paint</a>.
After the call, <a href="#SkPaint_move_constructor_paint">paint</a> is undefined, and can be safely destructed.
After the call, <a href="#SkPaint_move_SkPaint_paint">paint</a> is undefined, and can be safely destructed.
### Parameters
<table> <tr> <td><a name="SkPaint_move_constructor_paint"> <code><strong>paint </strong></code> </a></td> <td>
<table> <tr> <td><a name="SkPaint_move_SkPaint_paint"> <code><strong>paint </strong></code> </a></td> <td>
original to move</td>
</tr>
</table>
### Return Value
content of <a href="#SkPaint_move_constructor_paint">paint</a>
content of <a href="#SkPaint_move_SkPaint_paint">paint</a>
### Example
@ -643,7 +643,7 @@ by the client.
### Parameters
<table> <tr> <td><a name="SkPaint_unflatten_buffer"> <code><strong>buffer </strong></code> </a></td> <td>
serialized data to unflatten</td>
serialized data to <a href="#SkPaint_unflatten">unflatten</a></td>
</tr>
</table>
@ -4692,7 +4692,7 @@ double width = 10
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
size_t breakText(const void* text, size_t length, SkScalar maxWidth,
SkScalar* measuredWidth = NULL) const
SkScalar* measuredWidth = nullptr) const
</pre>
Returns the bytes of <a href="#SkPaint_breakText_text">text</a> that fit within <a href="#SkPaint_breakText_maxWidth">maxWidth</a>.
@ -4735,7 +4735,7 @@ bytes of <a href="#SkPaint_breakText_text">text</a> that fit, always less than o
<pre style="padding: 1em 1em 1em 1em;width: 50em; background-color: #f0f0f0">
int getTextWidths(const void* text, size_t byteLength, SkScalar widths[],
SkRect bounds[] = NULL) const
SkRect bounds[] = nullptr) const
</pre>
Retrieves the advance and <a href="#SkPaint_getTextWidths_bounds">bounds</a> for each glyph in <a href="#SkPaint_getTextWidths_text">text</a>, and returns

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,9 @@ Text Encoding anchors in paragraph are echoed instead of being linked to anchor
consts like enum members need fully qualfied refs to make a valid link
enum comments should be disallowed unless after #Enum and before first #Const
... or, should look for enum comments in other places
trouble with aliases, plurals
need to keep first letter of includeWriter @param / @return lowercase
Quad -> quad, Quads -> quads
*/
static string normalized_name(string name) {
@ -92,7 +94,8 @@ void Definition::setCanonicalFiddle() {
fMethodType = Definition::MethodType::kNone;
size_t doubleColons = fName.find("::", 0);
SkASSERT(string::npos != doubleColons);
string result = fName.substr(0, doubleColons) + "_";
string base = fName.substr(0, doubleColons);
string result = base + "_";
doubleColons += 2;
if (string::npos != fName.find('~', doubleColons)) {
fMethodType = Definition::MethodType::kDestructor;
@ -118,56 +121,69 @@ void Definition::setCanonicalFiddle() {
} else {
SkASSERT(0); // todo: incomplete
}
} else if (string::npos != fName.find("()", doubleColons)) {
if (isupper(fName[doubleColons])) {
fMethodType = Definition::MethodType::kConstructor;
result += "empty_constructor";
} else {
result += fName.substr(doubleColons, fName.length() - doubleColons - 2);
}
} else {
size_t comma = fName.find(',', doubleColons);
size_t openParen = fName.find('(', doubleColons);
if (string::npos == comma && string::npos != openParen) {
fMethodType = Definition::MethodType::kConstructor;
result += isMove ? "move_" : "copy_";
result += "constructor";
} else if (string::npos == openParen) {
result += fName.substr(doubleColons);
size_t parens = fName.find("()", doubleColons);
if (string::npos != parens) {
string methodName = fName.substr(doubleColons, parens - doubleColons);
do {
size_t nextDouble = methodName.find("::");
if (string::npos == nextDouble) {
break;
}
base = methodName.substr(0, nextDouble);
result += base + '_';
methodName = methodName.substr(nextDouble + 2);
doubleColons += nextDouble + 2;
} while (true);
if (base == methodName) {
fMethodType = Definition::MethodType::kConstructor;
result += "empty_constructor";
} else {
result += fName.substr(doubleColons, fName.length() - doubleColons - 2);
}
} else {
fMethodType = Definition::MethodType::kConstructor;
// name them by their param types, e.g. SkCanvas__int_int_const_SkSurfaceProps_star
SkASSERT(string::npos != openParen);
// TODO: move forward until parens are balanced and terminator =,)
TextParser params("", &fName[openParen] + 1, &*fName.end(), 0);
bool underline = false;
while (!params.eof()) {
// SkDEBUGCODE(const char* end = params.anyOf("(),=")); // unused for now
// SkASSERT(end[0] != '('); // fixme: put off handling nested parentheseses
if (params.startsWith("const") || params.startsWith("int")
|| params.startsWith("Sk")) {
const char* wordStart = params.fChar;
params.skipToNonAlphaNum();
if (underline) {
result += '_';
} else {
underline = true;
}
result += string(wordStart, params.fChar - wordStart);
} else {
params.skipToNonAlphaNum();
size_t openParen = fName.find('(', doubleColons);
if (string::npos == openParen) {
result += fName.substr(doubleColons);
} else {
size_t comma = fName.find(',', doubleColons);
if (string::npos == comma) {
result += isMove ? "move_" : "copy_";
}
if (!params.eof() && '*' == params.peek()) {
if (underline) {
result += '_';
fMethodType = Definition::MethodType::kConstructor;
// name them by their param types,
// e.g. SkCanvas__int_int_const_SkSurfaceProps_star
// TODO: move forward until parens are balanced and terminator =,)
TextParser params("", &fName[openParen] + 1, &*fName.end(), 0);
bool underline = false;
while (!params.eof()) {
// SkDEBUGCODE(const char* end = params.anyOf("(),=")); // unused for now
// SkASSERT(end[0] != '('); // fixme: put off handling nested parentheseses
if (params.startsWith("const") || params.startsWith("int")
|| params.startsWith("Sk")) {
const char* wordStart = params.fChar;
params.skipToNonAlphaNum();
if (underline) {
result += '_';
} else {
underline = true;
}
result += string(wordStart, params.fChar - wordStart);
} else {
underline = true;
params.skipToNonAlphaNum();
}
result += "star";
params.next();
params.skipSpace();
if (!params.eof() && '*' == params.peek()) {
if (underline) {
result += '_';
} else {
underline = true;
}
result += "star";
params.next();
params.skipSpace();
}
params.skipToAlpha();
}
params.skipToAlpha();
}
}
}
@ -391,13 +407,25 @@ bool Definition::checkMethod() const {
return true;
}
bool Definition::crossCheck(const char* tokenID, const Definition& includeToken) const {
const char* defStart = fStart;
SkASSERT('#' == defStart[0]); // FIXME: needs to be per definition
++defStart;
SkASSERT(!strncmp(defStart, tokenID, strlen(tokenID)));
defStart += strlen(tokenID);
return crossCheckInside(defStart, fContentStart, includeToken);
bool Definition::crossCheck2(const Definition& includeToken) const {
TextParser parser(fFileName, fStart, fContentStart, fLineCount);
parser.skipExact("#");
bool isMethod = parser.skipName("Method");
const char* contentEnd;
if (isMethod) {
contentEnd = fContentStart;
} else if (parser.skipName("DefinedBy")) {
contentEnd = fContentEnd;
while (parser.fChar < contentEnd && ' ' >= contentEnd[-1]) {
--contentEnd;
}
if (parser.fChar < contentEnd - 1 && ')' == contentEnd[-1] && '(' == contentEnd[-2]) {
contentEnd -= 2;
}
} else {
return parser.reportError<bool>("unexpected crosscheck marktype");
}
return crossCheckInside(parser.fChar, contentEnd, includeToken);
}
bool Definition::crossCheck(const Definition& includeToken) const {
@ -414,6 +442,9 @@ bool Definition::crossCheckInside(const char* start, const char* end,
if (inc.startsWith("friend")) {
inc.skipWord("friend");
}
if (inc.startsWith("SK_API")) {
inc.skipWord("SK_API");
}
do {
bool defEof;
bool incEof;
@ -763,6 +794,13 @@ const Definition* RootDefinition::find(const string& ref) const {
if (leafIter != fLeaves.end()) {
return &leafIter->second;
}
if (string::npos == ref.find("()")) {
string withParens = ref + "()";
const auto parensIter = fLeaves.find(withParens);
if (parensIter != fLeaves.end()) {
return &parensIter->second;
}
}
const auto branchIter = fBranches.find(ref);
if (branchIter != fBranches.end()) {
const RootDefinition* rootDef = branchIter->second;
@ -1006,7 +1044,7 @@ bool BmhParser::addDefinition(const char* defStart, bool hasEnd, MarkType markTy
fMarkup.emplace_front(markType, defStart, fLineCount, fParent);
definition = &fMarkup.front();
definition->fName = typeNameBuilder[0];
definition->fFiddle = normalized_name(typeNameBuilder[0]);
definition->fFiddle = fParent->fFiddle;
definition->fContentStart = fChar;
definition->fContentEnd = this->trimmedBracketEnd(fMC, OneLine::kYes);
this->skipToEndBracket(fMC);
@ -1139,6 +1177,54 @@ bool BmhParser::addDefinition(const char* defStart, bool hasEnd, MarkType markTy
return true;
}
void BmhParser::reportDuplicates(const Definition& def, const string& dup) const {
if (MarkType::kExample == def.fMarkType && dup == def.fFiddle) {
TextParser reporter(&def);
reporter.reportError("duplicate example name");
}
for (auto& child : def.fChildren ) {
reportDuplicates(*child, dup);
}
}
static void find_examples(const Definition& def, vector<string>* exampleNames) {
if (MarkType::kExample == def.fMarkType) {
exampleNames->push_back(def.fFiddle);
}
for (auto& child : def.fChildren ) {
find_examples(*child, exampleNames);
}
}
bool BmhParser::checkExamples() const {
vector<string> exampleNames;
for (const auto& topic : fTopicMap) {
if (topic.second->fParent) {
continue;
}
find_examples(*topic.second, &exampleNames);
}
std::sort(exampleNames.begin(), exampleNames.end());
string* last = nullptr;
string reported;
bool checkOK = true;
for (auto& nameIter : exampleNames) {
if (last && *last == nameIter && reported != *last) {
reported = *last;
SkDebugf("%s\n", reported.c_str());
for (const auto& topic : fTopicMap) {
if (topic.second->fParent) {
continue;
}
this->reportDuplicates(*topic.second, reported);
}
checkOK = false;
}
last = &nameIter;
}
return checkOK;
}
bool BmhParser::childOf(MarkType markType) const {
auto childError = [this](MarkType markType) -> bool {
string errStr = "expected ";
@ -1162,26 +1248,32 @@ bool BmhParser::childOf(MarkType markType) const {
}
string BmhParser::className(MarkType markType) {
string builder;
const Definition* parent = this->parentSpace();
if (parent && (parent != fParent || MarkType::kClass != markType)) {
builder += parent->fName;
}
const char* end = this->lineEnd();
const char* mc = this->strnchr(fMC, end);
string classID;
TextParser::Save savePlace(this);
this->skipSpace();
const char* wordStart = fChar;
this->skipToNonAlphaNum();
const char* wordEnd = fChar;
classID = string(wordStart, wordEnd - wordStart);
if (!mc) {
savePlace.restore();
}
string builder;
const Definition* parent = this->parentSpace();
if (parent && parent->fName != classID) {
builder += parent->fName;
}
if (mc) {
this->skipSpace();
const char* wordStart = fChar;
this->skipToNonAlphaNum();
const char* wordEnd = fChar;
if (mc + 1 < fEnd && fMC == mc[1]) { // if ##
if (markType != fParent->fMarkType) {
return this->reportError<string>("unbalanced method");
}
if (builder.length() > 0 && wordEnd > wordStart) {
if (builder.length() > 0 && classID.size() > 0) {
if (builder != fParent->fName) {
builder += "::";
builder += string(wordStart, wordEnd - wordStart);
builder += classID;
if (builder != fParent->fName) {
return this->reportError<string>("name mismatch");
}
@ -1241,6 +1333,49 @@ bool BmhParser::collectExternals() {
return true;
}
static bool dump_examples(FILE* fiddleOut, const Definition& def, bool* continuation) {
if (MarkType::kExample == def.fMarkType) {
string result;
if (!def.exampleToScript(&result)) {
return false;
}
if (result.length() > 0) {
if (*continuation) {
fprintf(fiddleOut, ",\n");
} else {
*continuation = true;
}
fprintf(fiddleOut, "%s", result.c_str());
}
return true;
}
for (auto& child : def.fChildren ) {
if (!dump_examples(fiddleOut, *child, continuation)) {
return false;
}
}
return true;
}
bool BmhParser::dumpExamples(const char* fiddleJsonFileName) const {
FILE* fiddleOut = fopen(fiddleJsonFileName, "wb");
if (!fiddleOut) {
SkDebugf("could not open output file %s\n", fiddleJsonFileName);
return false;
}
fprintf(fiddleOut, "{\n");
bool continuation = false;
for (const auto& topic : fTopicMap) {
if (topic.second->fParent) {
continue;
}
dump_examples(fiddleOut, *topic.second, &continuation);
}
fprintf(fiddleOut, "\n}\n");
fclose(fiddleOut);
return true;
}
int BmhParser::endHashCount() const {
const char* end = fLine + this->lineLength();
int count = 0;
@ -1976,30 +2111,6 @@ DEFINE_bool2(spellcheck, s, false, "Spell-check. (Requires -b)");
DEFINE_bool2(tokens, t, false, "Output include tokens. (Requires -i)");
DEFINE_bool2(crosscheck, x, false, "Check bmh against includes. (Requires -b -i)");
static bool dump_examples(FILE* fiddleOut, const Definition& def, bool* continuation) {
if (MarkType::kExample == def.fMarkType) {
string result;
if (!def.exampleToScript(&result)) {
return false;
}
if (result.length() > 0) {
if (*continuation) {
fprintf(fiddleOut, ",\n");
} else {
*continuation = true;
}
fprintf(fiddleOut, "%s", result.c_str());
}
return true;
}
for (auto& child : def.fChildren ) {
if (!dump_examples(fiddleOut, *child, continuation)) {
return false;
}
}
return true;
}
static int count_children(const Definition& def, MarkType markType) {
int count = 0;
if (markType == def.fMarkType) {
@ -2145,23 +2256,14 @@ int main(int argc, char** const argv) {
int examples = 0;
int methods = 0;
int topics = 0;
FILE* fiddleOut;
if (!done && !FLAGS_examples.isEmpty()) {
fiddleOut = fopen(FLAGS_examples[0], "wb");
if (!fiddleOut) {
SkDebugf("could not open output file %s\n", FLAGS_examples[0]);
// check to see if examples have duplicate names
if (!bmhParser.checkExamples()) {
return -1;
}
fprintf(fiddleOut, "{\n");
bool continuation = false;
for (const auto& topic : bmhParser.fTopicMap) {
if (topic.second->fParent) {
continue;
}
dump_examples(fiddleOut, *topic.second, &continuation);
if (!bmhParser.dumpExamples(FLAGS_examples[0])) {
return -1;
}
fprintf(fiddleOut, "\n}\n");
fclose(fiddleOut);
}
for (const auto& topic : bmhParser.fTopicMap) {
if (topic.second->fParent) {

View File

@ -40,6 +40,7 @@ using std::vector;
enum class KeyWord {
kNone,
kSK_API,
kBool,
kChar,
kClass,
@ -148,6 +149,7 @@ enum class Bracket {
kSlashSlash,
kPound,
kColon,
kDebugCode, // parens get special treatment so SkDEBUGCODE( isn't treated as method
};
enum class Punctuation { // catch-all for misc symbols tracked in C
@ -760,7 +762,7 @@ public:
bool checkMethod() const;
void setCanonicalFiddle();
bool crossCheck(const char* tokenName, const Definition& includeToken) const;
bool crossCheck2(const Definition& includeToken) const;
bool crossCheck(const Definition& includeToken) const;
bool crossCheckInside(const char* start, const char* end, const Definition& includeToken) const;
bool exampleToScript(string* result) const;
@ -1287,6 +1289,8 @@ public:
bool addDefinition(const char* defStart, bool hasEnd, MarkType markType,
const vector<string>& typeNameBuilder);
bool checkExamples() const;
bool dumpExamples(const char* fiddleJsonFileName) const;
bool childOf(MarkType markType) const;
string className(MarkType markType);
bool collectExternals();
@ -1316,6 +1320,7 @@ public:
}
bool popParentStack(Definition* definition);
void reportDuplicates(const Definition& def, const string& dup) const;
void reset() override {
INHERITED::resetCommon();
@ -1540,6 +1545,7 @@ public:
fRootTopic = nullptr;
fInBrace = nullptr;
fIncludeWord = nullptr;
fLastObject = nullptr;
fPrev = '\0';
fInChar = false;
fInCharCommentString = false;
@ -1602,6 +1608,7 @@ protected:
unordered_map<string, Definition> fIUnionMap;
Definition* fRootTopic;
Definition* fInBrace;
Definition* fLastObject;
const char* fIncludeWord;
char fPrev;
bool fInChar;
@ -1646,6 +1653,11 @@ public:
list<Definition>::iterator fDefEnd;
};
struct ParentPair {
const Definition* fParent;
const ParentPair* fPrev;
};
IncludeWriter() : IncludeParser() {}
~IncludeWriter() override {}
@ -1670,7 +1682,7 @@ public:
const int start, const int run, int lastWrite, const char last,
const char* data);
void methodOut(const Definition* method, const Definition& child);
bool populate(Definition* def, RootDefinition* root);
bool populate(Definition* def, ParentPair* parentPair, RootDefinition* root);
bool populate(BmhParser& bmhParser);
void reset() override {
@ -1680,6 +1692,7 @@ public:
fEnumDef = nullptr;
fMethodDef = nullptr;
fStructDef = nullptr;
fAttrDeprecated = nullptr;
fAnonymousEnumCount = 1;
fInStruct = false;
}
@ -1700,6 +1713,7 @@ private:
const Definition* fEnumDef;
const Definition* fMethodDef;
const Definition* fStructDef;
const Definition* fAttrDeprecated;
const char* fContinuation; // used to construct paren-qualified method name
int fAnonymousEnumCount;
int fEnumItemValueTab;

View File

@ -25,6 +25,7 @@ struct IncludeKey {
const IncludeKey kKeyWords[] = {
{ "", KeyWord::kNone, KeyProperty::kNone },
{ "SK_API", KeyWord::kSK_API, KeyProperty::kModifier },
{ "bool", KeyWord::kBool, KeyProperty::kNumber },
{ "char", KeyWord::kChar, KeyProperty::kNumber },
{ "class", KeyWord::kClass, KeyProperty::kObject },
@ -236,7 +237,6 @@ bool IncludeParser::crossCheck(BmhParser& bmhParser) {
if (this->internalName(token)) {
continue;
}
const char* methodID = bmhParser.fMaps[(int) token.fMarkType].fName;
if (!def) {
string paramName = className + "::";
paramName += string(token.fContentStart,
@ -303,12 +303,28 @@ bool IncludeParser::crossCheck(BmhParser& bmhParser) {
def = root->find(lowerName);
}
}
if (!def) {
if ("SK_ATTR_DEPRECATED" == token.fName) {
break;
}
if (0 == token.fName.find("SkDEBUGCODE")) {
break;
}
}
if (!def) {
// simple method names inside nested classes have a bug and are missing trailing parens
string withParens = fullName + "()"; // FIXME: this shouldn't be necessary
def = root->find(withParens);
}
if (!def) {
SkDebugf("method missing from bmh: %s\n", fullName.c_str());
break;
}
if (def->crossCheck(methodID, token)) {
if (def->crossCheck2(token)) {
def->fVisited = true;
if (MarkType::kDefinedBy == def->fMarkType) {
def->fParent->fVisited = true;
}
} else {
SkDebugf("method differs from bmh: %s\n", fullName.c_str());
}
@ -912,11 +928,13 @@ bool IncludeParser::parseClass(Definition* includeDef, IsStruct isStruct) {
iter = std::next(iter);
++lastPublic;
}
fLastObject = nullptr;
while (childIter != includeDef->fChildren.end() && (*childIter)->fParentIndex < lastPublic) {
Definition* child = *childIter;
if (!this->parseObject(child, markupDef)) {
return false;
}
fLastObject = child;
childIter = std::next(childIter);
}
while (childIter != includeDef->fChildren.end()) {
@ -1292,10 +1310,18 @@ bool IncludeParser::parseObject(Definition* child, Definition* markupDef) {
case Definition::Type::kBracket:
switch (child->fBracket) {
case Bracket::kParen:
if (fLastObject) {
TextParser checkDeprecated(child->fFileName, fLastObject->fTerminator + 1,
child->fStart, fLastObject->fLineCount);
checkDeprecated.skipWhiteSpace();
if (checkDeprecated.startsWith("SK_ATTR_DEPRECATED")) {
break;
}
}
if (!this->parseMethod(child, markupDef)) {
return this->reportError<bool>("failed to parse method");
}
break;
break;
case Bracket::kSlashSlash:
case Bracket::kSlashStar:
// comments are picked up by parsing objects first
@ -1336,6 +1362,9 @@ bool IncludeParser::parseObject(Definition* child, Definition* markupDef) {
case Bracket::kAngle:
// pick up templated function pieces when method is found
break;
case Bracket::kDebugCode:
// todo: handle this
break;
default:
return this->reportError<bool>("unhandled bracket");
}
@ -1457,6 +1486,11 @@ bool IncludeParser::parseChar() {
case '(':
case '[':
case '{': {
if (fIncludeWord && '(' == test && fChar - fIncludeWord >= 10 &&
!strncmp("SkDEBUGCODE", fIncludeWord, 10)) {
this->pushBracket(Bracket::kDebugCode);
break;
}
if (fInCharCommentString) {
break;
}
@ -1555,6 +1589,8 @@ bool IncludeParser::parseChar() {
} else {
fInFunction = '}' != test;
}
} else if (')' == test && Bracket::kDebugCode == this->topBracket()) {
this->popBracket();
} else {
return reportError<bool>("malformed close bracket");
}

View File

@ -268,6 +268,8 @@ void IncludeWriter::enumMembersOut(const RootDefinition* root, Definition& child
commentStart = privateDef->fContentStart;
commentLen = (int) (privateDef->fContentEnd - privateDef->fContentStart);
}
// FIXME: may assert here if there's no const value
// should have detected and errored on that earlier when enum fContentStart was set
SkASSERT(commentLen > 0 && commentLen < 1000);
if (!currentEnumItem->fShort) {
this->writeCommentHeader();
@ -508,6 +510,7 @@ void IncludeWriter::methodOut(const Definition* method, const Definition& child)
}
this->indentToColumn(column);
int partLen = (int) (partEnd - partStart);
// FIXME : detect this earlier; assert if #Return is empty
SkASSERT(partLen > 0 && partLen < 200);
fIndent = column;
this->rewriteBlock(partLen, partStart);
@ -673,6 +676,8 @@ void IncludeWriter::structSizeMembers(Definition& child) {
inMethod = false;
} else if (Punctuation::kLeftBrace == token.fPunctuation) {
inMethod = false;
} else if (Punctuation::kSemicolon == token.fPunctuation) {
inMethod = false;
} else {
SkASSERT(0); // incomplete
}
@ -735,7 +740,8 @@ void IncludeWriter::structSizeMembers(Definition& child) {
}
}
bool IncludeWriter::populate(Definition* def, RootDefinition* root) {
bool IncludeWriter::populate(Definition* def, ParentPair* prevPair, RootDefinition* root) {
ParentPair pair = { def, prevPair };
// write bulk of original include up to class, method, enum, etc., excepting preceding comment
// find associated bmh object
// write any associated comments in Doxygen form
@ -762,7 +768,8 @@ bool IncludeWriter::populate(Definition* def, RootDefinition* root) {
}
if (fContinuation) {
if (Definition::Type::kKeyWord == child.fType) {
if (KeyWord::kFriend == child.fKeyWord || KeyWord::kBool == child.fKeyWord) {
if (KeyWord::kFriend == child.fKeyWord || KeyWord::kBool == child.fKeyWord ||
KeyWord::kSK_API == child.fKeyWord) {
continue;
}
}
@ -875,14 +882,27 @@ bool IncludeWriter::populate(Definition* def, RootDefinition* root) {
continue;
}
this->methodOut(method, child);
if (fAttrDeprecated) {
fStart = fAttrDeprecated->fContentStart;
fAttrDeprecated = nullptr;
}
continue;
}
if (Definition::Type::kKeyWord == child.fType) {
const Definition* structDef = nullptr;
switch (child.fKeyWord) {
case KeyWord::kStruct:
case KeyWord::kClass:
// if struct contains members, compute their name and comment tabs
inStruct = fInStruct = child.fChildren.size() > 0;
if (child.fChildren.size() > 0) {
const ParentPair* testPair = &pair;
while ((testPair = testPair->fPrev)) {
if (KeyWord::kClass == testPair->fParent->fKeyWord) {
inStruct = fInStruct = true;
break;
}
}
}
if (fInStruct) {
fIndent += 4;
fStructDef = root->find(child.fName);
@ -892,11 +912,10 @@ bool IncludeWriter::populate(Definition* def, RootDefinition* root) {
this->structSizeMembers(child);
fIndent -= 4;
}
case KeyWord::kClass:
if (child.fChildren.size() > 0) {
const char* bodyEnd = fDeferComment ? fDeferComment->fContentStart - 1 :
child.fContentStart;
this->writeBlock((int) (bodyEnd - fStart), fStart);
this->writeBlockTrim((int) (bodyEnd - fStart), fStart);
fStart = child.fContentStart;
if (child.fName == root->fName) {
if (Definition* parent = root->fParent) {
@ -942,6 +961,7 @@ bool IncludeWriter::populate(Definition* def, RootDefinition* root) {
break;
}
}
// FIXME: trigger error earlier if inner #Struct or #Class is missing #Code
SkASSERT(nextBlock); // FIXME: check enum for correct order earlier
const char* commentStart = codeBlock->fTerminator;
const char* commentEnd = nextBlock->fStart;
@ -962,6 +982,7 @@ bool IncludeWriter::populate(Definition* def, RootDefinition* root) {
case KeyWord::kStatic:
case KeyWord::kInt:
case KeyWord::kUint32_t:
case KeyWord::kUnsigned:
case KeyWord::kSize_t:
case KeyWord::kFloat:
case KeyWord::kBool:
@ -974,6 +995,8 @@ bool IncludeWriter::populate(Definition* def, RootDefinition* root) {
case KeyWord::kPrivate:
case KeyWord::kProtected:
case KeyWord::kFriend:
case KeyWord::kInline:
case KeyWord::kSK_API:
case KeyWord::kTypedef:
break;
default:
@ -986,7 +1009,7 @@ bool IncludeWriter::populate(Definition* def, RootDefinition* root) {
this->writeBlock((int) (fStart - child.fStart), child.fStart);
this->lf(2);
fIndent += 4;
if (!this->populate(&child, const_cast<Definition*>(structDef)->asRoot())) {
if (!this->populate(&child, &pair, const_cast<Definition*>(structDef)->asRoot())) {
return false;
}
// output any remaining definitions at current indent level
@ -1001,10 +1024,10 @@ bool IncludeWriter::populate(Definition* def, RootDefinition* root) {
fDeferComment = nullptr;
} else {
if (fInEnum && KeyWord::kClass == child.fChildren[0]->fKeyWord) {
if (!this->populate(child.fChildren[0], root)) {
if (!this->populate(child.fChildren[0], &pair, root)) {
return false;
}
} else if (!this->populate(&child, root)) {
} else if (!this->populate(&child, &pair, root)) {
return false;
}
}
@ -1023,9 +1046,12 @@ bool IncludeWriter::populate(Definition* def, RootDefinition* root) {
fDeferComment = nullptr;
fInEnum = false;
continue;
}
}
if (fAttrDeprecated) {
continue;
}
fDeferComment = nullptr;
if (!this->populate(&child, root)) {
if (!this->populate(&child, &pair, root)) {
return false;
}
continue;
@ -1039,6 +1065,12 @@ bool IncludeWriter::populate(Definition* def, RootDefinition* root) {
if (child.fMemberStart) {
memberStart = &child;
}
const char attrDeprecated[] = "SK_ATTR_DEPRECATED";
const size_t attrDeprecatedLen = sizeof(attrDeprecated) - 1;
if (attrDeprecatedLen == child.fContentEnd - child.fContentStart &&
!strncmp(attrDeprecated, child.fStart, attrDeprecatedLen)) {
fAttrDeprecated = &child;
}
continue;
}
if (Definition::Type::kPunctuation == child.fType) {
@ -1086,7 +1118,7 @@ bool IncludeWriter::populate(BmhParser& bmhParser) {
root->clearVisited();
fStart = includeMapper.second.fContentStart;
fEnd = includeMapper.second.fContentEnd;
allPassed &= this->populate(&includeMapper.second, root);
allPassed &= this->populate(&includeMapper.second, nullptr, root);
this->writeBlock((int) (fEnd - fStart), fStart);
fIndent = 0;
this->lfcr();
@ -1409,7 +1441,7 @@ IncludeWriter::Wrote IncludeWriter::rewriteBlock(int size, const char* data) {
case '\'': // possessive apostrophe isn't treated as delimiting punctation
case '=':
case '!': // assumed not to be punctuation, but a programming symbol
case '&': case '>': case '<': case '{': case '}': case '/': case '*':
case '&': case '>': case '<': case '{': case '}': case '/': case '*': case '[': case ']':
word = Word::kMixed;
embeddedSymbol = true;
break;
@ -1442,6 +1474,10 @@ IncludeWriter::Wrote IncludeWriter::rewriteBlock(int size, const char* data) {
}
hasSymbol |= embeddedSymbol;
break;
case '+':
// hackery to allow C++
SkASSERT('C' == last || '+' == last); // FIXME: don't allow + outside of #Formula
break;
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':