2020-06-02 15:34:24 +00:00
/*
* Copyright 2020 Google Inc .
*
* Use of this source code is governed by a BSD - style license that can be
* found in the LICENSE file .
*/
# include "gm/gm.h"
# include "include/core/SkCanvas.h"
# include "include/core/SkColor.h"
# include "include/core/SkFont.h"
# include "include/core/SkFontTypes.h"
# include "include/core/SkPaint.h"
# include "include/core/SkPoint.h"
# include "include/core/SkRect.h"
# include "include/core/SkScalar.h"
# include "include/core/SkShader.h"
# include "include/core/SkSize.h"
# include "include/core/SkString.h"
# include "include/core/SkTypeface.h"
# include "tools/ToolUtils.h"
# include "modules/skparagraph/include/Paragraph.h"
2020-09-11 13:59:49 +00:00
# include "modules/skparagraph/src/ParagraphBuilderImpl.h"
2020-06-02 15:34:24 +00:00
static const char * gSpeach = " Five score years ago, a great American, in whose symbolic shadow we stand today, signed the Emancipation Proclamation. This momentous decree came as a great beacon light of hope to millions of Negro slaves who had been seared in the flames of withering injustice. It came as a joyous daybreak to end the long night of their captivity. " ;
namespace {
enum ParaFlags {
kTimeLayout = 1 < < 0 ,
kUseUnderline = 1 < < 1 ,
2021-04-16 15:59:00 +00:00
kShowVisitor = 1 < < 2 ,
2020-06-02 15:34:24 +00:00
} ;
2020-08-06 18:11:56 +00:00
} // namespace
2020-06-02 15:34:24 +00:00
class ParagraphGM : public skiagm : : GM {
std : : unique_ptr < skia : : textlayout : : Paragraph > fPara ;
const unsigned fFlags ;
public :
ParagraphGM ( unsigned flags ) : fFlags ( flags ) { }
void buildParagraph ( ) {
skia : : textlayout : : TextStyle style ;
style . setForegroundColor ( SkPaint ( ) ) ;
style . setFontFamilies ( { SkString ( " sans-serif " ) } ) ;
style . setFontSize ( 30 ) ;
if ( fFlags & kUseUnderline ) {
style . setDecoration ( skia : : textlayout : : TextDecoration : : kUnderline ) ;
style . setDecorationMode ( skia : : textlayout : : TextDecorationMode : : kThrough ) ;
style . setDecorationColor ( SK_ColorBLACK ) ;
style . setDecorationThicknessMultiplier ( 2 ) ;
}
skia : : textlayout : : ParagraphStyle paraStyle ;
paraStyle . setTextStyle ( style ) ;
auto collection = sk_make_sp < skia : : textlayout : : FontCollection > ( ) ;
collection - > setDefaultFontManager ( SkFontMgr : : RefDefault ( ) ) ;
2020-09-11 13:59:49 +00:00
auto builder = skia : : textlayout : : ParagraphBuilderImpl : : make ( paraStyle , collection ) ;
if ( nullptr = = builder ) {
fPara = nullptr ;
return ;
}
2020-06-02 15:34:24 +00:00
builder - > addText ( gSpeach , strlen ( gSpeach ) ) ;
fPara = builder - > Build ( ) ;
fPara - > layout ( 400 ) ;
}
protected :
void onOnceBeforeDraw ( ) override {
this - > buildParagraph ( ) ;
}
SkString onShortName ( ) override {
SkString name ;
name . printf ( " paragraph%s_%s " ,
fFlags & kTimeLayout ? " _layout " : " " ,
fFlags & kUseUnderline ? " _underline " : " " ) ;
2021-04-16 15:59:00 +00:00
if ( fFlags & kShowVisitor ) {
name . append ( " _visitor " ) ;
}
2020-06-02 15:34:24 +00:00
return name ;
}
2021-04-16 15:59:00 +00:00
SkISize onISize ( ) override {
if ( fFlags & kShowVisitor ) {
2021-04-16 17:08:57 +00:00
return SkISize : : Make ( 810 , 420 ) ;
2021-04-16 15:59:00 +00:00
}
return SkISize : : Make ( 412 , 420 ) ;
}
void drawFromVisitor ( SkCanvas * canvas , skia : : textlayout : : Paragraph * para ) const {
2021-04-30 20:48:24 +00:00
SkPaint p , p2 ;
2021-04-16 15:59:00 +00:00
p . setColor ( 0xFF0000FF ) ;
2021-04-30 20:48:24 +00:00
p2 . setColor ( 0xFFFF0000 ) ;
p2 . setStrokeWidth ( 4 ) ;
p2 . setStrokeCap ( SkPaint : : kSquare_Cap ) ;
2021-05-14 13:53:30 +00:00
SkPaint underp ;
underp . setStroke ( true ) ;
underp . setStrokeWidth ( 2 ) ;
underp . setAntiAlias ( true ) ;
underp . setColor ( p . getColor ( ) ) ;
const SkScalar GAP = 2 ;
2021-04-30 20:48:24 +00:00
2021-05-02 21:47:09 +00:00
para - > visit ( [ & ] ( int , const skia : : textlayout : : Paragraph : : VisitorInfo * info ) {
if ( ! info ) {
return ;
}
canvas - > drawGlyphs ( info - > count , info - > glyphs , info - > positions , info - > origin ,
info - > font , p ) ;
2021-04-16 15:59:00 +00:00
2021-05-14 13:53:30 +00:00
if ( fFlags & kUseUnderline ) {
// Need to modify positions to roll-in the orign
std : : vector < SkPoint > pos ;
for ( int i = 0 ; i < info - > count ; + + i ) {
pos . push_back ( { info - > origin . fX + info - > positions [ i ] . fX ,
info - > origin . fY + info - > positions [ i ] . fY } ) ;
}
const SkScalar X0 = pos [ 0 ] . fX ;
const SkScalar X1 = X0 + info - > advanceX ;
const SkScalar Y = pos [ 0 ] . fY ;
auto sects = info - > font . getIntercepts ( info - > glyphs , info - > count , pos . data ( ) ,
Y + 1 , Y + 3 ) ;
SkScalar x0 = X0 ;
for ( size_t i = 0 ; i < sects . size ( ) ; i + = 2 ) {
SkScalar x1 = sects [ i ] - GAP ;
if ( x0 < x1 ) {
canvas - > drawLine ( x0 , Y + 2 , x1 , Y + 2 , underp ) ;
}
x0 = sects [ i + 1 ] + GAP ;
}
canvas - > drawLine ( x0 , Y + 2 , X1 , Y + 2 , underp ) ;
}
2021-05-02 21:47:09 +00:00
if ( info - > utf8Starts & & false ) {
2021-04-16 15:59:00 +00:00
SkString str ;
2021-05-02 21:47:09 +00:00
for ( int i = 0 ; i < info - > count ; + + i ) {
str . appendUnichar ( gSpeach [ info - > utf8Starts [ i ] ] ) ;
2021-04-16 15:59:00 +00:00
}
SkDebugf ( " '%s' \n " , str . c_str ( ) ) ;
}
2021-04-30 20:48:24 +00:00
if ( false ) { // show position points
2021-05-02 21:47:09 +00:00
for ( int i = 0 ; i < info - > count ; + + i ) {
auto pos = info - > positions [ i ] ;
canvas - > drawPoint ( pos . fX + info - > origin . fX , pos . fY + info - > origin . fY , p2 ) ;
2021-04-30 20:48:24 +00:00
}
}
2021-04-16 15:59:00 +00:00
} ) ;
}
2020-06-02 15:34:24 +00:00
DrawResult onDraw ( SkCanvas * canvas , SkString * errorMsg ) override {
2020-09-11 13:59:49 +00:00
if ( nullptr = = fPara ) {
return DrawResult : : kSkip ;
}
2021-04-16 15:59:00 +00:00
if ( fFlags & kShowVisitor ) {
canvas - > clear ( SK_ColorWHITE ) ;
fPara - > layout ( 400 ) ;
fPara - > paint ( canvas , 10 , 10 ) ;
canvas - > translate ( 400 + 10 , 10 ) ;
this - > drawFromVisitor ( canvas , fPara . get ( ) ) ;
return DrawResult : : kOk ;
}
2020-06-02 15:34:24 +00:00
const int loop = ( this - > getMode ( ) = = kGM_Mode ) ? 1 : 50 ;
int parity = 0 ;
for ( int i = 0 ; i < loop ; + + i ) {
SkAutoCanvasRestore acr ( canvas , true ) ;
if ( fFlags & kTimeLayout ) {
fPara - > layout ( 400 + parity ) ;
parity = ( parity + 1 ) & 1 ;
}
fPara - > paint ( canvas , 10 , 10 ) ;
}
// clean up if we've been looping
if ( loop > 1 ) {
canvas - > clear ( SK_ColorWHITE ) ;
fPara - > layout ( 400 ) ;
fPara - > paint ( canvas , 10 , 10 ) ;
}
if ( ( this - > getMode ( ) = = kGM_Mode ) & & ( fFlags & kTimeLayout ) ) {
return DrawResult : : kSkip ;
}
return DrawResult : : kOk ;
}
bool runAsBench ( ) const override { return true ; }
bool onAnimate ( double /*nanos*/ ) override {
2021-04-30 20:48:24 +00:00
return false ;
2020-06-02 15:34:24 +00:00
}
private :
2020-09-03 02:42:33 +00:00
using INHERITED = skiagm : : GM ;
2020-06-02 15:34:24 +00:00
} ;
DEF_GM ( return new ParagraphGM ( 0 ) ; )
DEF_GM ( return new ParagraphGM ( kTimeLayout ) ; )
DEF_GM ( return new ParagraphGM ( kUseUnderline ) ; )
2021-04-16 15:59:00 +00:00
DEF_GM ( return new ParagraphGM ( kShowVisitor ) ; )
2021-05-14 13:53:30 +00:00
DEF_GM ( return new ParagraphGM ( kShowVisitor | kUseUnderline ) ; )