2019-10-03 15:22:08 +00:00
/*
* Copyright 2019 Google LLC
*
* Use of this source code is governed by a BSD - style license that can be
* found in the LICENSE file .
*/
# include "include/core/SkColor.h"
2019-10-21 14:50:26 +00:00
# include "include/core/SkFontStyle.h"
2019-10-03 15:22:08 +00:00
# include "include/core/SkString.h"
# include "modules/skparagraph/include/DartTypes.h"
# include "modules/skparagraph/include/Paragraph.h"
# include "modules/skparagraph/include/ParagraphBuilder.h"
# include "modules/skparagraph/include/TextStyle.h"
2020-08-04 20:21:09 +00:00
# include "modules/skparagraph/include/TypefaceFontProvider.h"
2019-10-03 15:22:08 +00:00
# include "modules/skparagraph/src/ParagraphBuilderImpl.h"
# include "modules/skparagraph/src/ParagraphImpl.h"
# include <string>
# include <vector>
# include <emscripten.h>
# include <emscripten/bind.h>
2020-03-26 13:27:48 +00:00
# include "modules/canvaskit/WasmCommon.h"
2019-10-03 15:22:08 +00:00
using namespace emscripten ;
namespace para = skia : : textlayout ;
2020-05-04 20:46:17 +00:00
SkColor4f toSkColor4f ( uintptr_t /* float* */ cPtr ) {
float * fourFloats = reinterpret_cast < float * > ( cPtr ) ;
SkColor4f color = { fourFloats [ 0 ] , fourFloats [ 1 ] , fourFloats [ 2 ] , fourFloats [ 3 ] } ;
return color ;
}
2019-10-21 14:50:26 +00:00
struct SimpleFontStyle {
SkFontStyle : : Slant slant ;
SkFontStyle : : Weight weight ;
SkFontStyle : : Width width ;
} ;
2019-10-03 15:22:08 +00:00
struct SimpleTextStyle {
2020-05-04 20:46:17 +00:00
uintptr_t /* float* */ colorPtr ;
uintptr_t /* float* */ foregroundColorPtr ;
uintptr_t /* float* */ backgroundColorPtr ;
2019-10-03 15:22:08 +00:00
uint8_t decoration ;
SkScalar decorationThickness ;
2019-10-21 14:50:26 +00:00
SkScalar fontSize ;
SimpleFontStyle fontStyle ;
2020-05-14 12:27:53 +00:00
uintptr_t /* const char** */ fontFamiliesPtr ;
int fontFamiliesLen ;
2019-10-03 15:22:08 +00:00
} ;
para : : TextStyle toTextStyle ( const SimpleTextStyle & s ) {
para : : TextStyle ts ;
2020-03-26 13:27:48 +00:00
// textstyle.color doesn't support a 4f color, however the foreground and background fields below do.
2020-05-04 20:46:17 +00:00
ts . setColor ( toSkColor4f ( s . colorPtr ) . toSkColor ( ) ) ;
2020-03-26 13:27:48 +00:00
// It is functionally important that these paints be unset when no value was provided.
2020-05-04 20:46:17 +00:00
if ( s . foregroundColorPtr ) {
2020-03-26 13:27:48 +00:00
SkPaint p1 ;
2020-05-04 20:46:17 +00:00
p1 . setColor4f ( toSkColor4f ( s . foregroundColorPtr ) ) ;
2020-03-26 13:27:48 +00:00
ts . setForegroundColor ( p1 ) ;
2020-03-24 14:19:40 +00:00
}
2020-03-24 13:08:37 +00:00
2020-05-04 20:46:17 +00:00
if ( s . backgroundColorPtr ) {
2020-03-26 13:27:48 +00:00
SkPaint p2 ;
2020-05-04 20:46:17 +00:00
p2 . setColor4f ( toSkColor4f ( s . backgroundColorPtr ) ) ;
2020-03-26 13:27:48 +00:00
ts . setBackgroundColor ( p2 ) ;
2020-03-24 14:19:40 +00:00
}
2019-10-03 15:22:08 +00:00
if ( s . fontSize ! = 0 ) {
ts . setFontSize ( s . fontSize ) ;
}
ts . setDecoration ( para : : TextDecoration ( s . decoration ) ) ;
if ( s . decorationThickness ! = 0 ) {
ts . setDecorationThicknessMultiplier ( s . decorationThickness ) ;
}
2020-05-14 12:27:53 +00:00
const char * * fontFamilies = reinterpret_cast < const char * * > ( s . fontFamiliesPtr ) ;
if ( s . fontFamiliesLen > 0 & & fontFamilies ! = nullptr ) {
2019-10-03 15:22:08 +00:00
std : : vector < SkString > ff ;
2020-05-14 12:27:53 +00:00
for ( int i = 0 ; i < s . fontFamiliesLen ; i + + ) {
2019-10-03 15:22:08 +00:00
ff . emplace_back ( fontFamilies [ i ] ) ;
}
ts . setFontFamilies ( ff ) ;
}
2019-10-21 14:50:26 +00:00
SkFontStyle fs ( s . fontStyle . weight , s . fontStyle . width , s . fontStyle . slant ) ;
ts . setFontStyle ( fs ) ;
2019-10-03 15:22:08 +00:00
return ts ;
}
struct SimpleParagraphStyle {
2019-10-21 14:50:26 +00:00
bool disableHinting ;
uintptr_t /* const char* */ ellipsisPtr ;
size_t ellipsisLen ;
2019-10-03 15:22:08 +00:00
SkScalar heightMultiplier ;
size_t maxLines ;
2019-10-21 14:50:26 +00:00
para : : TextAlign textAlign ;
para : : TextDirection textDirection ;
SimpleTextStyle textStyle ;
2019-10-03 15:22:08 +00:00
} ;
para : : ParagraphStyle toParagraphStyle ( const SimpleParagraphStyle & s ) {
para : : ParagraphStyle ps ;
2019-10-21 14:50:26 +00:00
if ( s . disableHinting ) {
ps . turnHintingOff ( ) ;
}
if ( s . ellipsisLen > 0 ) {
const char * ellipsisPtr = reinterpret_cast < const char * > ( s . ellipsisPtr ) ;
SkString eStr ( ellipsisPtr , s . ellipsisLen ) ;
ps . setEllipsis ( eStr ) ;
}
ps . setTextAlign ( s . textAlign ) ;
ps . setTextDirection ( s . textDirection ) ;
2019-10-03 15:22:08 +00:00
auto ts = toTextStyle ( s . textStyle ) ;
ps . setTextStyle ( ts ) ;
if ( s . heightMultiplier ! = 0 ) {
ps . setHeight ( s . heightMultiplier ) ;
}
if ( s . maxLines ! = 0 ) {
ps . setMaxLines ( s . maxLines ) ;
}
return ps ;
}
2019-11-20 13:27:10 +00:00
struct SimpleTextBox {
SkRect rect ;
// This isn't the most efficient way to represent this, but it is much easier to keep
// everything as floats when unpacking on the JS side.
// 0.0 = RTL, 1.0 = LTr
SkScalar direction ;
} ;
2019-10-03 15:22:08 +00:00
Float32Array GetRectsForRange ( para : : ParagraphImpl & self , unsigned start , unsigned end ,
para : : RectHeightStyle heightStyle , para : : RectWidthStyle widthStyle ) {
std : : vector < para : : TextBox > boxes = self . getRectsForRange ( start , end , heightStyle , widthStyle ) ;
2019-11-20 13:27:10 +00:00
// Pack these text boxes into an array of n groups of 5 SkScalar (floats)
2019-10-03 15:22:08 +00:00
if ( ! boxes . size ( ) ) {
return emscripten : : val : : null ( ) ;
}
2019-11-20 13:27:10 +00:00
SimpleTextBox * rects = new SimpleTextBox [ boxes . size ( ) ] ;
2019-10-03 15:22:08 +00:00
for ( int i = 0 ; i < boxes . size ( ) ; i + + ) {
2019-11-20 13:27:10 +00:00
rects [ i ] . rect = boxes [ i ] . rect ;
if ( boxes [ i ] . direction = = para : : TextDirection : : kRtl ) {
rects [ i ] . direction = 0 ;
} else {
rects [ i ] . direction = 1 ;
}
2019-10-03 15:22:08 +00:00
}
float * fPtr = reinterpret_cast < float * > ( rects ) ;
// Of note: now that we have cast rects to float*, emscripten is smart enough to wrap this
// into a Float32Array for us.
2019-11-20 13:27:10 +00:00
return Float32Array ( typed_memory_view ( boxes . size ( ) * 5 , fPtr ) ) ;
2019-10-03 15:22:08 +00:00
}
EMSCRIPTEN_BINDINGS ( Paragraph ) {
class_ < para : : Paragraph > ( " Paragraph " ) ;
// This "base<>" tells Emscripten that ParagraphImpl is a Paragraph and can get substituted
// in properly in drawParagraph. However, Emscripten will not let us bind pure virtual methods
2019-11-15 19:48:55 +00:00
// so we have to "expose" the ParagraphImpl in those cases.
2019-10-03 15:22:08 +00:00
class_ < para : : ParagraphImpl , base < para : : Paragraph > > ( " ParagraphImpl " )
2019-11-15 19:48:55 +00:00
. function ( " didExceedMaxLines " , & para : : Paragraph : : didExceedMaxLines )
. function ( " getAlphabeticBaseline " , & para : : Paragraph : : getAlphabeticBaseline )
2019-10-03 15:22:08 +00:00
. function ( " getGlyphPositionAtCoordinate " , & para : : ParagraphImpl : : getGlyphPositionAtCoordinate )
2019-11-15 19:48:55 +00:00
. function ( " getHeight " , & para : : Paragraph : : getHeight )
. function ( " getIdeographicBaseline " , & para : : Paragraph : : getIdeographicBaseline )
. function ( " getLongestLine " , & para : : Paragraph : : getLongestLine )
. function ( " getMaxIntrinsicWidth " , & para : : Paragraph : : getMaxIntrinsicWidth )
. function ( " getMaxWidth " , & para : : Paragraph : : getMaxWidth )
. function ( " getMinIntrinsicWidth " , & para : : Paragraph : : getMinIntrinsicWidth )
. function ( " _getRectsForRange " , & GetRectsForRange )
. function ( " getWordBoundary " , & para : : ParagraphImpl : : getWordBoundary )
2019-10-03 15:22:08 +00:00
. function ( " layout " , & para : : ParagraphImpl : : layout ) ;
class_ < para : : ParagraphBuilderImpl > ( " ParagraphBuilder " )
2020-09-11 13:59:49 +00:00
. class_function ( " _Make " , optional_override ( [ ] ( SimpleParagraphStyle style , sk_sp < SkFontMgr > fontMgr )
- > std : : unique_ptr < para : : ParagraphBuilderImpl > {
2019-10-03 15:22:08 +00:00
auto fc = sk_make_sp < para : : FontCollection > ( ) ;
fc - > setDefaultFontManager ( fontMgr ) ;
auto ps = toParagraphStyle ( style ) ;
2020-09-11 13:59:49 +00:00
auto pb = para : : ParagraphBuilderImpl : : make ( ps , fc ) ;
return std : : unique_ptr < para : : ParagraphBuilderImpl > ( static_cast < para : : ParagraphBuilderImpl * > ( pb . release ( ) ) ) ;
2019-10-03 15:22:08 +00:00
} ) , allow_raw_pointers ( ) )
2020-08-04 20:21:09 +00:00
. class_function ( " _MakeFromFontProvider " , optional_override ( [ ] ( SimpleParagraphStyle style ,
2020-09-11 13:59:49 +00:00
sk_sp < para : : TypefaceFontProvider > fontProvider ) - > std : : unique_ptr < para : : ParagraphBuilderImpl > {
2020-08-04 20:21:09 +00:00
auto fc = sk_make_sp < para : : FontCollection > ( ) ;
fc - > setDefaultFontManager ( fontProvider ) ;
auto ps = toParagraphStyle ( style ) ;
2020-09-11 13:59:49 +00:00
auto pb = para : : ParagraphBuilderImpl : : make ( ps , fc ) ;
return std : : unique_ptr < para : : ParagraphBuilderImpl > ( static_cast < para : : ParagraphBuilderImpl * > ( pb . release ( ) ) ) ;
2020-08-04 20:21:09 +00:00
} ) , allow_raw_pointers ( ) )
2019-10-03 15:22:08 +00:00
. function ( " addText " , optional_override ( [ ] ( para : : ParagraphBuilderImpl & self , std : : string text ) {
return self . addText ( text . c_str ( ) , text . length ( ) ) ;
} ) )
. function ( " build " , & para : : ParagraphBuilderImpl : : Build , allow_raw_pointers ( ) )
. function ( " pop " , & para : : ParagraphBuilderImpl : : pop )
2020-05-04 20:46:17 +00:00
. function ( " _pushStyle " , optional_override ( [ ] ( para : : ParagraphBuilderImpl & self ,
2019-10-03 15:22:08 +00:00
SimpleTextStyle textStyle ) {
auto ts = toTextStyle ( textStyle ) ;
self . pushStyle ( ts ) ;
2020-08-04 13:06:54 +00:00
} ) )
// A method of pushing a textStyle with paints instead of colors for foreground and
// background. Since SimpleTextStyle is a value object, it cannot contain paints, which are not primitives. This binding is here to accept them. Any color that is specified in the textStyle is overridden.
. function ( " _pushPaintStyle " , optional_override ( [ ] ( para : : ParagraphBuilderImpl & self ,
SimpleTextStyle textStyle , SkPaint foreground , SkPaint background ) {
auto ts = toTextStyle ( textStyle ) ;
ts . setForegroundColor ( foreground ) ;
ts . setBackgroundColor ( background ) ;
self . pushStyle ( ts ) ;
2019-10-03 15:22:08 +00:00
} ) ) ;
2020-08-04 20:21:09 +00:00
class_ < para : : TypefaceFontProvider , base < SkFontMgr > > ( " TypefaceFontProvider " )
. smart_ptr < sk_sp < para : : TypefaceFontProvider > > ( " sk_sp<TypefaceFontProvider> " )
. class_function ( " Make " , optional_override ( [ ] ( ) - > sk_sp < para : : TypefaceFontProvider > {
return sk_make_sp < para : : TypefaceFontProvider > ( ) ;
} ) )
. function ( " _registerFont " , optional_override ( [ ] ( para : : TypefaceFontProvider & self ,
sk_sp < SkTypeface > typeface ,
uintptr_t familyPtr ) {
const char * fPtr = reinterpret_cast < const char * > ( familyPtr ) ;
SkString fStr ( fPtr ) ;
self . registerTypeface ( typeface , fStr ) ;
} ) , allow_raw_pointers ( ) ) ;
2019-10-03 15:22:08 +00:00
enum_ < para : : Affinity > ( " Affinity " )
. value ( " Upstream " , para : : Affinity : : kUpstream )
. value ( " Downstream " , para : : Affinity : : kDownstream ) ;
2019-10-21 14:50:26 +00:00
enum_ < SkFontStyle : : Slant > ( " FontSlant " )
. value ( " Upright " , SkFontStyle : : Slant : : kUpright_Slant )
. value ( " Italic " , SkFontStyle : : Slant : : kItalic_Slant )
. value ( " Oblique " , SkFontStyle : : Slant : : kOblique_Slant ) ;
enum_ < SkFontStyle : : Weight > ( " FontWeight " )
. value ( " Invisible " , SkFontStyle : : Weight : : kInvisible_Weight )
. value ( " Thin " , SkFontStyle : : Weight : : kThin_Weight )
. value ( " ExtraLight " , SkFontStyle : : Weight : : kExtraLight_Weight )
. value ( " Light " , SkFontStyle : : Weight : : kLight_Weight )
. value ( " Normal " , SkFontStyle : : Weight : : kNormal_Weight )
. value ( " Medium " , SkFontStyle : : Weight : : kMedium_Weight )
. value ( " SemiBold " , SkFontStyle : : Weight : : kSemiBold_Weight )
. value ( " Bold " , SkFontStyle : : Weight : : kBold_Weight )
. value ( " ExtraBold " , SkFontStyle : : Weight : : kExtraBold_Weight )
. value ( " Black " , SkFontStyle : : Weight : : kBlack_Weight )
. value ( " ExtraBlack " , SkFontStyle : : Weight : : kExtraBlack_Weight ) ;
enum_ < SkFontStyle : : Width > ( " FontWidth " )
. value ( " UltraCondensed " , SkFontStyle : : Width : : kUltraCondensed_Width )
. value ( " ExtraCondensed " , SkFontStyle : : Width : : kExtraCondensed_Width )
. value ( " Condensed " , SkFontStyle : : Width : : kCondensed_Width )
. value ( " SemiCondensed " , SkFontStyle : : Width : : kSemiCondensed_Width )
. value ( " Normal " , SkFontStyle : : Width : : kNormal_Width )
. value ( " SemiExpanded " , SkFontStyle : : Width : : kSemiExpanded_Width )
. value ( " Expanded " , SkFontStyle : : Width : : kExpanded_Width )
. value ( " ExtraExpanded " , SkFontStyle : : Width : : kExtraExpanded_Width )
. value ( " UltraExpanded " , SkFontStyle : : Width : : kUltraExpanded_Width ) ;
2019-10-03 15:22:08 +00:00
enum_ < para : : RectHeightStyle > ( " RectHeightStyle " )
2019-11-20 13:27:10 +00:00
. value ( " Tight " , para : : RectHeightStyle : : kTight )
. value ( " Max " , para : : RectHeightStyle : : kMax )
. value ( " IncludeLineSpacingMiddle " , para : : RectHeightStyle : : kIncludeLineSpacingMiddle )
. value ( " IncludeLineSpacingTop " , para : : RectHeightStyle : : kIncludeLineSpacingTop )
. value ( " IncludeLineSpacingBottom " , para : : RectHeightStyle : : kIncludeLineSpacingBottom ) ;
2019-10-03 15:22:08 +00:00
enum_ < para : : RectWidthStyle > ( " RectWidthStyle " )
. value ( " Tight " , para : : RectWidthStyle : : kTight )
. value ( " Max " , para : : RectWidthStyle : : kMax ) ;
enum_ < para : : TextAlign > ( " TextAlign " )
. value ( " Left " , para : : TextAlign : : kLeft )
. value ( " Right " , para : : TextAlign : : kRight )
. value ( " Center " , para : : TextAlign : : kCenter )
. value ( " Justify " , para : : TextAlign : : kJustify )
. value ( " Start " , para : : TextAlign : : kStart )
. value ( " End " , para : : TextAlign : : kEnd ) ;
2019-10-21 14:50:26 +00:00
enum_ < para : : TextDirection > ( " TextDirection " )
. value ( " LTR " , para : : TextDirection : : kLtr )
. value ( " RTL " , para : : TextDirection : : kRtl ) ;
2019-10-03 15:22:08 +00:00
value_object < para : : PositionWithAffinity > ( " PositionWithAffinity " )
. field ( " pos " , & para : : PositionWithAffinity : : position )
. field ( " affinity " , & para : : PositionWithAffinity : : affinity ) ;
2019-11-15 19:48:55 +00:00
value_object < SimpleFontStyle > ( " FontStyle " )
2019-10-21 14:50:26 +00:00
. field ( " slant " , & SimpleFontStyle : : slant )
. field ( " weight " , & SimpleFontStyle : : weight )
. field ( " width " , & SimpleFontStyle : : width ) ;
2019-10-03 15:22:08 +00:00
value_object < SimpleParagraphStyle > ( " ParagraphStyle " )
2019-10-21 14:50:26 +00:00
. field ( " disableHinting " , & SimpleParagraphStyle : : disableHinting )
. field ( " _ellipsisPtr " , & SimpleParagraphStyle : : ellipsisPtr )
. field ( " _ellipsisLen " , & SimpleParagraphStyle : : ellipsisLen )
2019-10-03 15:22:08 +00:00
. field ( " heightMultiplier " , & SimpleParagraphStyle : : heightMultiplier )
. field ( " maxLines " , & SimpleParagraphStyle : : maxLines )
. field ( " textAlign " , & SimpleParagraphStyle : : textAlign )
2019-10-21 14:50:26 +00:00
. field ( " textDirection " , & SimpleParagraphStyle : : textDirection )
2019-10-03 15:22:08 +00:00
. field ( " textStyle " , & SimpleParagraphStyle : : textStyle ) ;
value_object < SimpleTextStyle > ( " TextStyle " )
2020-05-14 12:27:53 +00:00
. field ( " _colorPtr " , & SimpleTextStyle : : colorPtr )
. field ( " _foregroundColorPtr " , & SimpleTextStyle : : foregroundColorPtr )
. field ( " _backgroundColorPtr " , & SimpleTextStyle : : backgroundColorPtr )
2019-10-03 15:22:08 +00:00
. field ( " decoration " , & SimpleTextStyle : : decoration )
. field ( " decorationThickness " , & SimpleTextStyle : : decorationThickness )
2020-05-14 12:27:53 +00:00
. field ( " _fontFamiliesPtr " , & SimpleTextStyle : : fontFamiliesPtr )
. field ( " _fontFamiliesLen " , & SimpleTextStyle : : fontFamiliesLen )
2019-10-03 15:22:08 +00:00
. field ( " fontSize " , & SimpleTextStyle : : fontSize )
2020-05-14 12:27:53 +00:00
. field ( " fontStyle " , & SimpleTextStyle : : fontStyle ) ;
2019-10-03 15:22:08 +00:00
2019-11-15 19:48:55 +00:00
// The U stands for unsigned - we can't bind a generic/template object, so we have to specify it
// with the type we are using.
value_object < para : : SkRange < size_t > > ( " URange " )
. field ( " start " , & para : : SkRange < size_t > : : start )
. field ( " end " , & para : : SkRange < size_t > : : end ) ;
2019-10-03 15:22:08 +00:00
// TextDecoration should be a const because they can be combined
constant ( " NoDecoration " , int ( para : : TextDecoration : : kNoDecoration ) ) ;
constant ( " UnderlineDecoration " , int ( para : : TextDecoration : : kUnderline ) ) ;
constant ( " OverlineDecoration " , int ( para : : TextDecoration : : kOverline ) ) ;
constant ( " LineThroughDecoration " , int ( para : : TextDecoration : : kLineThrough ) ) ;
}