Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
qq_34031325
engine
提交
02daceb2
E
engine
项目概览
qq_34031325
/
engine
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
engine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
02daceb2
编写于
8月 08, 2020
作者:
M
Mouad Debbar
提交者:
GitHub
8月 08, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[web] Implement support for WidgetSpan (aka paragraph placeholders) (#20276)
上级
ece90428
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
215 addition
and
5 deletion
+215
-5
lib/web_ui/lib/src/engine/text/measurement.dart
lib/web_ui/lib/src/engine/text/measurement.dart
+3
-0
lib/web_ui/lib/src/engine/text/paragraph.dart
lib/web_ui/lib/src/engine/text/paragraph.dart
+110
-5
lib/web_ui/lib/src/engine/text/ruler.dart
lib/web_ui/lib/src/engine/text/ruler.dart
+28
-0
lib/web_ui/test/golden_tests/engine/text_placeholders_test.dart
...b_ui/test/golden_tests/engine/text_placeholders_test.dart
+74
-0
未找到文件。
lib/web_ui/lib/src/engine/text/measurement.dart
浏览文件 @
02daceb2
...
...
@@ -448,6 +448,7 @@ class DomTextMeasurementService extends TextMeasurementService {
alphabeticBaseline:
alphabeticBaseline
,
ideographicBaseline:
ideographicBaseline
,
lines:
lines
,
placeholderBoxes:
ruler
.
measurePlaceholderBoxes
(),
textAlign:
paragraph
.
_textAlign
,
textDirection:
paragraph
.
_textDirection
,
);
...
...
@@ -498,6 +499,7 @@ class DomTextMeasurementService extends TextMeasurementService {
alphabeticBaseline:
alphabeticBaseline
,
ideographicBaseline:
ideographicBaseline
,
lines:
null
,
placeholderBoxes:
ruler
.
measurePlaceholderBoxes
(),
textAlign:
paragraph
.
_textAlign
,
textDirection:
paragraph
.
_textDirection
,
);
...
...
@@ -609,6 +611,7 @@ class CanvasTextMeasurementService extends TextMeasurementService {
maxIntrinsicWidth:
maxIntrinsicCalculator
.
value
,
width:
constraints
.
width
,
lines:
linesCalculator
.
lines
,
placeholderBoxes:
<
ui
.
TextBox
>[],
textAlign:
paragraph
.
_textAlign
,
textDirection:
paragraph
.
_textDirection
,
);
...
...
lib/web_ui/lib/src/engine/text/paragraph.dart
浏览文件 @
02daceb2
...
...
@@ -7,6 +7,8 @@ part of engine;
const
ui
.
Color
_defaultTextColor
=
ui
.
Color
(
0xFFFF0000
);
const
String
_placeholderClass
=
'paragraph-placeholder'
;
class
EngineLineMetrics
implements
ui
.
LineMetrics
{
EngineLineMetrics
({
required
this
.
hardBreak
,
...
...
@@ -174,6 +176,7 @@ class EngineParagraph implements ui.Paragraph {
required
ui
.
TextAlign
textAlign
,
required
ui
.
TextDirection
textDirection
,
required
ui
.
Paint
?
background
,
required
this
.
placeholderCount
,
})
:
assert
((
plainText
==
null
&&
paint
==
null
)
||
(
plainText
!=
null
&&
paint
!=
null
)),
_paragraphElement
=
paragraphElement
,
...
...
@@ -192,6 +195,8 @@ class EngineParagraph implements ui.Paragraph {
final
ui
.
TextDirection
_textDirection
;
final
SurfacePaint
?
_background
;
final
int
placeholderCount
;
@visibleForTesting
String
?
get
plainText
=>
_plainText
;
...
...
@@ -332,7 +337,8 @@ class EngineParagraph implements ui.Paragraph {
@override
List
<
ui
.
TextBox
>
getBoxesForPlaceholders
()
{
return
const
<
ui
.
TextBox
>[];
assert
(
_isLaidOut
);
return
_measurementResult
!.
placeholderBoxes
;
}
/// Returns `true` if this paragraph can be directly painted to the canvas.
...
...
@@ -482,6 +488,7 @@ class EngineParagraph implements ui.Paragraph {
textAlign:
_textAlign
,
textDirection:
_textDirection
,
background:
_background
,
placeholderCount:
placeholderCount
,
);
}
...
...
@@ -1058,11 +1065,11 @@ class EngineParagraphBuilder implements ui.ParagraphBuilder {
@override
int
get
placeholderCount
=>
_placeholderCount
;
late
int
_placeholderCount
;
int
_placeholderCount
=
0
;
@override
List
<
double
>
get
placeholderScales
=>
_placeholderScales
;
List
<
double
>
_placeholderScales
=
<
double
>[];
final
List
<
double
>
_placeholderScales
=
<
double
>[];
@override
void
addPlaceholder
(
...
...
@@ -1073,8 +1080,20 @@ class EngineParagraphBuilder implements ui.ParagraphBuilder {
double
?
baselineOffset
,
ui
.
TextBaseline
?
baseline
,
})
{
// TODO(garyq): Implement stub_ui version of this.
throw
UnimplementedError
();
// Require a baseline to be specified if using a baseline-based alignment.
assert
((
alignment
==
ui
.
PlaceholderAlignment
.
aboveBaseline
||
alignment
==
ui
.
PlaceholderAlignment
.
belowBaseline
||
alignment
==
ui
.
PlaceholderAlignment
.
baseline
)
?
baseline
!=
null
:
true
);
_placeholderCount
++;
_placeholderScales
.
add
(
scale
);
_ops
.
add
(
ParagraphPlaceholder
(
width
*
scale
,
height
*
scale
,
alignment
,
baselineOffset:
(
baselineOffset
??
height
)
*
scale
,
baseline:
baseline
??
ui
.
TextBaseline
.
alphabetic
,
));
}
// TODO(yjbanov): do we need to do this?
...
...
@@ -1253,6 +1272,7 @@ class EngineParagraphBuilder implements ui.ParagraphBuilder {
textAlign:
textAlign
,
textDirection:
textDirection
,
background:
cumulativeStyle
.
_background
,
placeholderCount:
placeholderCount
,
);
}
...
...
@@ -1307,6 +1327,7 @@ class EngineParagraphBuilder implements ui.ParagraphBuilder {
textAlign:
textAlign
,
textDirection:
textDirection
,
background:
cumulativeStyle
.
_background
,
placeholderCount:
placeholderCount
,
);
}
...
...
@@ -1315,6 +1336,7 @@ class EngineParagraphBuilder implements ui.ParagraphBuilder {
final
List
<
dynamic
>
elementStack
=
<
dynamic
>[];
dynamic
currentElement
()
=>
elementStack
.
isNotEmpty
?
elementStack
.
last
:
_paragraphElement
;
for
(
int
i
=
0
;
i
<
_ops
.
length
;
i
++)
{
final
dynamic
op
=
_ops
[
i
];
if
(
op
is
EngineTextStyle
)
{
...
...
@@ -1327,6 +1349,11 @@ class EngineParagraphBuilder implements ui.ParagraphBuilder {
elementStack
.
add
(
span
);
}
else
if
(
op
is
String
)
{
domRenderer
.
appendText
(
currentElement
(),
op
);
}
else
if
(
op
is
ParagraphPlaceholder
)
{
domRenderer
.
append
(
currentElement
(),
_createPlaceholderElement
(
placeholder:
op
),
);
}
else
if
(
identical
(
op
,
_paragraphBuilderPop
))
{
elementStack
.
removeLast
();
}
else
{
...
...
@@ -1350,10 +1377,42 @@ class EngineParagraphBuilder implements ui.ParagraphBuilder {
textAlign:
_paragraphStyle
.
_effectiveTextAlign
,
textDirection:
_paragraphStyle
.
_effectiveTextDirection
,
background:
null
,
placeholderCount:
placeholderCount
,
);
}
}
/// Holds information for a placeholder in a paragraph.
///
/// [width], [height] and [baselineOffset] are expected to be already scaled.
class
ParagraphPlaceholder
{
ParagraphPlaceholder
(
this
.
width
,
this
.
height
,
this
.
alignment
,
{
required
this
.
baselineOffset
,
required
this
.
baseline
,
});
/// The scaled width of the placeholder.
final
double
width
;
/// The scaled height of the placeholder.
final
double
height
;
/// Specifies how the placeholder rectangle will be vertically aligned with
/// the surrounding text.
final
ui
.
PlaceholderAlignment
alignment
;
/// When the [alignment] value is [ui.PlaceholderAlignment.baseline], the
/// [baselineOffset] indicates the distance from the baseline to the top of
/// the placeholder rectangle.
final
double
baselineOffset
;
/// Dictates whether to use alphabetic or ideographic baseline.
final
ui
.
TextBaseline
baseline
;
}
/// Converts [fontWeight] to its CSS equivalent value.
String
?
fontWeightToCss
(
ui
.
FontWeight
?
fontWeight
)
{
if
(
fontWeight
==
null
)
{
...
...
@@ -1568,6 +1627,52 @@ void _applyTextStyleToElement({
}
}
html
.
Element
_createPlaceholderElement
(
{
required
ParagraphPlaceholder
placeholder
,
})
{
final
html
.
Element
element
=
domRenderer
.
createElement
(
'span'
);
element
.
className
=
_placeholderClass
;
final
html
.
CssStyleDeclaration
style
=
element
.
style
;
style
..
display
=
'inline-block'
..
width
=
'
${placeholder.width}
px'
..
height
=
'
${placeholder.height}
px'
..
verticalAlign
=
_placeholderAlignmentToCssVerticalAlign
(
placeholder
);
return
element
;
}
String
_placeholderAlignmentToCssVerticalAlign
(
ParagraphPlaceholder
placeholder
,
)
{
// For more details about the vertical-align CSS property, see:
// - https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align
switch
(
placeholder
.
alignment
)
{
case
ui
.
PlaceholderAlignment
.
top
:
return
'top'
;
case
ui
.
PlaceholderAlignment
.
middle
:
return
'middle'
;
case
ui
.
PlaceholderAlignment
.
bottom
:
return
'bottom'
;
case
ui
.
PlaceholderAlignment
.
aboveBaseline
:
return
'baseline'
;
case
ui
.
PlaceholderAlignment
.
belowBaseline
:
return
'-
${placeholder.height}
px'
;
case
ui
.
PlaceholderAlignment
.
baseline
:
// In CSS, the placeholder is already placed above the baseline. But
// Flutter's `baselineOffset` assumes the placeholder is placed below the
// baseline. That's why we need to subtract the placeholder's height from
// `baselineOffset`.
final
double
offset
=
placeholder
.
baselineOffset
-
placeholder
.
height
;
return
'
${offset}
px'
;
}
}
String
_shadowListToCss
(
List
<
ui
.
Shadow
>
shadows
)
{
if
(
shadows
.
isEmpty
)
{
return
''
;
...
...
lib/web_ui/lib/src/engine/text/ruler.dart
浏览文件 @
02daceb2
...
...
@@ -628,6 +628,31 @@ class ParagraphRuler {
);
}
List
<
ui
.
TextBox
>
measurePlaceholderBoxes
()
{
assert
(!
_debugIsDisposed
);
assert
(
_paragraph
!=
null
);
if
(
_paragraph
!.
placeholderCount
==
0
)
{
return
const
<
ui
.
TextBox
>[];
}
final
List
<
html
.
Element
>
placeholderElements
=
constrainedDimensions
.
_element
.
querySelectorAll
(
'.
$_placeholderClass
'
);
final
List
<
ui
.
TextBox
>
boxes
=
<
ui
.
TextBox
>[];
for
(
final
html
.
Element
element
in
placeholderElements
)
{
final
html
.
Rectangle
<
num
>
rect
=
element
.
getBoundingClientRect
();
boxes
.
add
(
ui
.
TextBox
.
fromLTRBD
(
rect
.
left
as
double
,
rect
.
top
as
double
,
rect
.
right
as
double
,
rect
.
bottom
as
double
,
_paragraph
!.
_textDirection
,
));
}
return
boxes
;
}
/// Returns text position in a paragraph that contains multiple
/// nested spans given an offset.
int
hitTest
(
ui
.
ParagraphConstraints
constraints
,
ui
.
Offset
offset
)
{
...
...
@@ -905,6 +930,8 @@ class MeasurementResult {
/// of each laid out line.
final
List
<
EngineLineMetrics
>?
lines
;
final
List
<
ui
.
TextBox
>
placeholderBoxes
;
/// The text align value of the paragraph.
final
ui
.
TextAlign
textAlign
;
...
...
@@ -923,6 +950,7 @@ class MeasurementResult {
required
this
.
alphabeticBaseline
,
required
this
.
ideographicBaseline
,
required
this
.
lines
,
required
this
.
placeholderBoxes
,
required
ui
.
TextAlign
?
textAlign
,
required
ui
.
TextDirection
?
textDirection
,
})
:
assert
(
constraintWidth
!=
null
),
// ignore: unnecessary_null_comparison
...
...
lib/web_ui/test/golden_tests/engine/text_placeholders_test.dart
0 → 100644
浏览文件 @
02daceb2
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
// import 'package:image/image.dart';
import
'package:ui/src/engine.dart'
;
import
'package:ui/ui.dart'
;
import
'scuba.dart'
;
typedef
PaintTest
=
void
Function
(
RecordingCanvas
recordingCanvas
);
void
main
(
)
async
{
final
EngineScubaTester
scuba
=
await
EngineScubaTester
.
initialize
(
viewportSize:
const
Size
(
600
,
600
),
);
setUpStableTestFonts
();
testEachCanvas
(
'draws paragraphs with placeholders'
,
(
EngineCanvas
canvas
)
{
final
Rect
screenRect
=
const
Rect
.
fromLTWH
(
0
,
0
,
600
,
600
);
final
RecordingCanvas
recordingCanvas
=
RecordingCanvas
(
screenRect
);
Offset
offset
=
Offset
.
zero
;
for
(
PlaceholderAlignment
alignment
in
PlaceholderAlignment
.
values
)
{
_paintTextWithPlaceholder
(
recordingCanvas
,
offset
,
alignment
);
offset
=
offset
.
translate
(
0.0
,
80.0
);
}
recordingCanvas
.
endRecording
();
recordingCanvas
.
apply
(
canvas
,
screenRect
);
return
scuba
.
diffCanvasScreenshot
(
canvas
,
'text_with_placeholders'
);
},
bSkipHoudini:
true
);
}
const
Color
black
=
Color
(
0xFF000000
);
const
Color
blue
=
Color
(
0xFF0000FF
);
const
Color
red
=
Color
(
0xFFFF0000
);
const
Size
placeholderSize
=
Size
(
80.0
,
50.0
);
void
_paintTextWithPlaceholder
(
RecordingCanvas
canvas
,
Offset
offset
,
PlaceholderAlignment
alignment
,
)
{
// First let's draw the paragraph.
final
Paragraph
paragraph
=
_createParagraphWithPlaceholder
(
alignment
);
canvas
.
drawParagraph
(
paragraph
,
offset
);
// Then fill the placeholders.
final
TextBox
placeholderBox
=
paragraph
.
getBoxesForPlaceholders
().
single
;
canvas
.
drawRect
(
placeholderBox
.
toRect
().
shift
(
offset
),
Paint
()..
color
=
red
,
);
}
Paragraph
_createParagraphWithPlaceholder
(
PlaceholderAlignment
alignment
)
{
final
ParagraphBuilder
builder
=
ParagraphBuilder
(
ParagraphStyle
());
builder
.
pushStyle
(
TextStyle
(
color:
black
,
fontFamily:
'Roboto'
,
fontSize:
14
));
builder
.
addText
(
'Lorem ipsum'
);
builder
.
addPlaceholder
(
placeholderSize
.
width
,
placeholderSize
.
height
,
alignment
,
baselineOffset:
40.0
,
baseline:
TextBaseline
.
alphabetic
,
);
builder
.
pushStyle
(
TextStyle
(
color:
blue
,
fontFamily:
'Roboto'
,
fontSize:
14
));
builder
.
addText
(
'dolor sit amet, consectetur.'
);
return
builder
.
build
()..
layout
(
ParagraphConstraints
(
width:
200.0
));
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录