Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
4e5cf5ef
Unverified
Commit
4e5cf5ef
authored
5 years ago
by
Gary Qian
Committed by
GitHub
5 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Reland "Text inline widgets, TextSpan rework" (#33946)" (#34002)
This reverts commit
14414f35
.
parent
3dd87ff7
Changes
26
Hide whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
240 additions
and
2443 deletions
+240
-2443
main.dart
dev/benchmarks/complex_layout/lib/main.dart
+2
-2
text.dart
dev/manual_tests/lib/text.dart
+1
-1
painting.dart
packages/flutter/lib/painting.dart
+1
-3
time_picker.dart
packages/flutter/lib/src/material/time_picker.dart
+1
-2
inline_span.dart
packages/flutter/lib/src/painting/inline_span.dart
+0
-249
placeholder_span.dart
packages/flutter/lib/src/painting/placeholder_span.dart
+0
-85
text_painter.dart
packages/flutter/lib/src/painting/text_painter.dart
+13
-134
text_span.dart
packages/flutter/lib/src/painting/text_span.dart
+117
-116
box.dart
packages/flutter/lib/src/rendering/box.dart
+1
-4
debug_overflow_indicator.dart
...s/flutter/lib/src/rendering/debug_overflow_indicator.dart
+2
-2
paragraph.dart
packages/flutter/lib/src/rendering/paragraph.dart
+65
-330
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+4
-20
text.dart
packages/flutter/lib/src/widgets/text.dart
+3
-10
widget_inspector.dart
packages/flutter/lib/src/widgets/widget_inspector.dart
+1
-2
widget_span.dart
packages/flutter/lib/src/widgets/widget_span.dart
+0
-198
widgets.dart
packages/flutter/lib/widgets.dart
+0
-1
text_painter_rtl_test.dart
packages/flutter/test/painting/text_painter_rtl_test.dart
+4
-8
text_painter_test.dart
packages/flutter/test/painting/text_painter_test.dart
+0
-95
text_span_test.dart
packages/flutter/test/painting/text_span_test.dart
+7
-132
paragraph_test.dart
packages/flutter/test/rendering/paragraph_test.dart
+0
-90
backdrop_filter_test.dart
packages/flutter/test/widgets/backdrop_filter_test.dart
+0
-1
basic_test.dart
packages/flutter/test/widgets/basic_test.dart
+1
-0
editable_text_test.dart
packages/flutter/test/widgets/editable_text_test.dart
+2
-3
text_golden_test.dart
packages/flutter/test/widgets/text_golden_test.dart
+12
-815
text_test.dart
packages/flutter/test/widgets/text_test.dart
+2
-136
widget_inspector_test.dart
packages/flutter/test/widgets/widget_inspector_test.dart
+1
-4
No files found.
dev/benchmarks/complex_layout/lib/main.dart
View file @
4e5cf5ef
...
...
@@ -438,8 +438,8 @@ class ItemImageBox extends StatelessWidget {
borderRadius:
BorderRadius
.
circular
(
2.0
),
),
padding:
const
EdgeInsets
.
all
(
4.0
),
child:
RichText
(
text:
const
TextSpan
(
child:
const
RichText
(
text:
TextSpan
(
style:
TextStyle
(
color:
Colors
.
white
),
children:
<
TextSpan
>[
TextSpan
(
...
...
This diff is collapsed.
Click to expand it.
dev/manual_tests/lib/text.dart
View file @
4e5cf5ef
...
...
@@ -145,7 +145,7 @@ class _FuzzerState extends State<Fuzzer> with SingleTickerProviderStateMixin {
return
TextSpan
(
text:
_fiddleWithText
(
node
.
text
),
style:
_fiddleWithStyle
(
node
.
style
),
children:
_fiddleWithChildren
(
node
.
children
?.
map
((
InlineSpan
child
)
=>
_fiddleWith
(
child
))?.
toList
()
??
<
Inline
Span
>[]),
children:
_fiddleWithChildren
(
node
.
children
?.
map
((
TextSpan
child
)
=>
_fiddleWith
(
child
))?.
toList
()
??
<
Text
Span
>[]),
);
}
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/painting.dart
View file @
4e5cf5ef
...
...
@@ -17,7 +17,7 @@
/// painting boxes.
library
painting
;
export
'dart:ui'
show
Shadow
,
PlaceholderAlignment
;
export
'dart:ui'
show
Shadow
;
export
'src/painting/alignment.dart'
;
export
'src/painting/basic_types.dart'
;
...
...
@@ -46,11 +46,9 @@ export 'src/painting/image_decoder.dart';
export
'src/painting/image_provider.dart'
;
export
'src/painting/image_resolution.dart'
;
export
'src/painting/image_stream.dart'
;
export
'src/painting/inline_span.dart'
;
export
'src/painting/matrix_utils.dart'
;
export
'src/painting/notched_shapes.dart'
;
export
'src/painting/paint_utilities.dart'
;
export
'src/painting/placeholder_span.dart'
;
export
'src/painting/rounded_rectangle_border.dart'
;
export
'src/painting/shader_warm_up.dart'
;
export
'src/painting/shape_decoration.dart'
;
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/material/time_picker.dart
View file @
4e5cf5ef
...
...
@@ -993,7 +993,6 @@ class _DialPainter extends CustomPainter {
final
double
width
=
labelPainter
.
width
*
_semanticNodeSizeScale
;
final
double
height
=
labelPainter
.
height
*
_semanticNodeSizeScale
;
final
Offset
nodeOffset
=
getOffsetForTheta
(
labelTheta
,
ring
)
+
Offset
(-
width
/
2.0
,
-
height
/
2.0
);
final
TextSpan
textSpan
=
labelPainter
.
text
;
final
CustomPainterSemantics
node
=
CustomPainterSemantics
(
rect:
Rect
.
fromLTRB
(
nodeOffset
.
dx
-
24.0
+
width
/
2
,
...
...
@@ -1004,7 +1003,7 @@ class _DialPainter extends CustomPainter {
properties:
SemanticsProperties
(
sortKey:
OrdinalSortKey
(
i
.
toDouble
()
+
ordinalOffset
),
selected:
label
.
value
==
selectedValue
,
value:
textSpan
?
.
text
,
value:
labelPainter
.
text
.
text
,
textDirection:
textDirection
,
onTap:
label
.
onTap
,
),
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/painting/inline_span.dart
deleted
100644 → 0
View file @
3dd87ff7
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:ui'
as
ui
show
ParagraphBuilder
;
import
'package:flutter/foundation.dart'
;
import
'basic_types.dart'
;
import
'text_painter.dart'
;
import
'text_style.dart'
;
/// Mutable wrapper of an integer that can be passed by reference to track a
/// value across a recursive stack.
class
Accumulator
{
/// [Accumulator] may be initialized with a specified value, otherwise, it will
/// initialize to zero.
Accumulator
([
this
.
_value
=
0
]);
/// The integer stored in this [Accumulator].
int
get
value
=>
_value
;
int
_value
;
/// Increases the [value] by the `addend`.
void
increment
(
int
addend
)
{
assert
(
addend
>=
0
);
_value
+=
addend
;
}
}
/// Called on each span as [InlineSpan.visitChildren] walks the [InlineSpan] tree.
///
/// Returns true when the walk should continue, and false to stop visiting further
/// [InlineSpan]s.
typedef
InlineSpanVisitor
=
bool
Function
(
InlineSpan
span
);
/// An immutable span of inline content which forms part of a paragraph.
///
/// * The subclass [TextSpan] specifies text and may contain child [InlineSpan]s.
/// * The subclass [PlaceholderSpan] represents a placeholder that may be
/// filled with non-text content. [PlaceholderSpan] itself defines a
/// [ui.PlaceholderAlignemnt] and a [TextBaseline]. To be useful,
/// [PlaceholderSpan] must be extended to define content. An instance of
/// this is the [WidgetSpan] class in the widgets library.
/// * The subclass [WidgetSpan] specifies embedded inline widgets.
///
/// {@tool sample}
///
/// This example shows a tree of [InlineSpan]s that make a query asking for a
/// name with a [TextField] embedded inline.
///
/// ```dart
/// Text.rich(
/// TextSpan(
/// text: 'My name is ',
/// style: TextStyle(color: Colors.black),
/// children: <InlineSpan>[
/// WidgetSpan(
/// alignment: PlaceholderAlignment.baseline,
/// baseline: TextBaseline.alphabetic,
/// child: ConstrainedBox(
/// constraints: BoxConstraints(maxWidth: 100),
/// child: TextField(),
/// )
/// ),
/// TextSpan(
/// text: '.',
/// ),
/// ],
/// ),
/// )
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [Text], a widget for showing uniformly-styled text.
/// * [RichText], a widget for finer control of text rendering.
/// * [TextPainter], a class for painting [InlineSpan] objects on a [Canvas].
@immutable
abstract
class
InlineSpan
extends
DiagnosticableTree
{
/// Creates an [InlineSpan] with the given values.
const
InlineSpan
({
this
.
style
,
});
/// The [TextStyle] to apply to this span.
///
/// The [style] is also applied to any child spans when this is an instance
/// of [TextSpan].
final
TextStyle
style
;
/// Apply the properties of this object to the given [ParagraphBuilder], from
/// which a [Paragraph] can be obtained.
///
/// The `textScaleFactor` parameter specifies a scale that the text and
/// placeholders will be scaled by. The scaling is performed before layout,
/// so the text will be laid out with the scaled glyphs and placeholders.
///
/// The `dimensions` parameter specifies the sizes of the placeholders.
/// Each [PlaceholderSpan] must be paired with a [PlaceholderDimensions]
/// in the same order as defined in the [InlineSpan] tree.
///
/// [Paragraph] objects can be drawn on [Canvas] objects.
void
build
(
ui
.
ParagraphBuilder
builder
,
{
double
textScaleFactor
=
1.0
,
List
<
PlaceholderDimensions
>
dimensions
});
/// Walks this [InlineSpan] and any descendants in pre-order and calls `visitor`
/// for each span that has content.
///
/// When `visitor` returns true, the walk will continue. When `visitor` returns
/// false, then the walk will end.
bool
visitChildren
(
InlineSpanVisitor
visitor
);
/// Returns the text span that contains the given position in the text.
InlineSpan
getSpanForPosition
(
TextPosition
position
)
{
assert
(
debugAssertIsValid
());
final
Accumulator
offset
=
Accumulator
();
InlineSpan
result
;
visitChildren
((
InlineSpan
span
)
{
result
=
span
.
getSpanForPositionVisitor
(
position
,
offset
);
return
result
==
null
;
});
return
result
;
}
/// Performs the check at each [InlineSpan] for if the `position` falls within the range
/// of the span and returns the span if it does.
///
/// The `offset` parameter tracks the current index offset in the text buffer formed
/// if the contents of the [InlineSpan] tree were concatenated together starting
/// from the root [InlineSpan].
///
/// This method should not be directly called. Use [getSpanForPosition] instead.
@protected
InlineSpan
getSpanForPositionVisitor
(
TextPosition
position
,
Accumulator
offset
);
/// Flattens the [InlineSpan] tree into a single string.
///
/// Styles are not honored in this process. If `includeSemanticsLabels` is
/// true, then the text returned will include the [TextSpan.semanticsLabel]s
/// instead of the text contents for [TextSpan]s.
///
/// When `includePlaceholders` is true, [PlaceholderSpan]s in the tree will be
/// represented as a 0xFFFC 'object replacement character'.
String
toPlainText
({
bool
includeSemanticsLabels
=
true
,
bool
includePlaceholders
=
true
})
{
final
StringBuffer
buffer
=
StringBuffer
();
computeToPlainText
(
buffer
,
includeSemanticsLabels:
includeSemanticsLabels
,
includePlaceholders:
includePlaceholders
);
return
buffer
.
toString
();
}
/// Walks the [InlineSpan] tree and writes the plain text representation to `buffer`.
///
/// This method should not be directly called. Use [toPlainText] instead.
///
/// Styles are not honored in this process. If `includeSemanticsLabels` is
/// true, then the text returned will include the [TextSpan.semanticsLabel]s
/// instead of the text contents for [TextSpan]s.
///
/// When `includePlaceholders` is true, [PlaceholderSpan]s in the tree will be
/// represented as a 0xFFFC 'object replacement character'.
///
/// The plain-text representation of this [InlineSpan] is written into the `buffer`.
/// This method will then recursively call [computeToPlainText] on its childen
/// [InlineSpan]s if available.
@protected
void
computeToPlainText
(
StringBuffer
buffer
,
{
bool
includeSemanticsLabels
=
true
,
bool
includePlaceholders
=
true
});
/// Returns the UTF-16 code unit at the given `index` in the flattened string.
///
/// This only accounts for the [TextSpan.text] values and ignores [PlaceholderSpans].
///
/// Returns null if the `index` is out of bounds.
int
codeUnitAt
(
int
index
)
{
if
(
index
<
0
)
return
null
;
final
Accumulator
offset
=
Accumulator
();
int
result
;
visitChildren
((
InlineSpan
span
)
{
result
=
span
.
codeUnitAtVisitor
(
index
,
offset
);
return
result
==
null
;
});
return
result
;
}
/// Performs the check at each [InlineSpan] for if the `index` falls within the range
/// of the span and returns the corresponding code unit. Returns null otherwise.
///
/// The `offset` parameter tracks the current index offset in the text buffer formed
/// if the contents of the [InlineSpan] tree were concatenated together starting
/// from the root [InlineSpan].
///
/// This method should not be directly called. Use [codeUnitAt] instead.
@protected
int
codeUnitAtVisitor
(
int
index
,
Accumulator
offset
);
/// Populates the `semanticsOffsets` and `semanticsElements` with the appropriate data
/// to be able to construct a [SemanticsNode].
///
/// If applicable, the beginning and end text offset are added to [semanticsOffsets].
/// [PlaceholderSpan]s have a text length of 1, which corresponds to the object
/// replacement character (0xFFFC) that is inserted to represent it.
///
/// Any [GestureRecognizer]s are added to `semanticsElements`. Null is added to
/// `semanticsElements` for [PlaceholderSpan]s.
void
describeSemantics
(
Accumulator
offset
,
List
<
int
>
semanticsOffsets
,
List
<
dynamic
>
semanticsElements
);
/// In checked mode, throws an exception if the object is not in a
/// valid configuration. Otherwise, returns true.
///
/// This is intended to be used as follows:
///
/// ```dart
/// assert(myInlineSpan.debugAssertIsValid());
/// ```
bool
debugAssertIsValid
()
=>
true
;
/// Describe the difference between this span and another, in terms of
/// how much damage it will make to the rendering. The comparison is deep.
///
/// Comparing [InlineSpan] objects of different types, for example, comparing
/// a [TextSpan] to a [WidgetSpan], always results in [RenderComparison.layout].
///
/// See also:
///
/// * [TextStyle.compareTo], which does the same thing for [TextStyle]s.
RenderComparison
compareTo
(
InlineSpan
other
);
@override
bool
operator
==(
dynamic
other
)
{
if
(
identical
(
this
,
other
))
return
true
;
if
(
other
.
runtimeType
!=
runtimeType
)
return
false
;
final
InlineSpan
typedOther
=
other
;
return
typedOther
.
style
==
style
;
}
@override
int
get
hashCode
=>
style
.
hashCode
;
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
properties
.
defaultDiagnosticsTreeStyle
=
DiagnosticsTreeStyle
.
whitespace
;
if
(
style
!=
null
)
{
style
.
debugFillProperties
(
properties
);
}
}
}
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/painting/placeholder_span.dart
deleted
100644 → 0
View file @
3dd87ff7
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:ui'
as
ui
show
PlaceholderAlignment
;
import
'package:flutter/foundation.dart'
;
import
'basic_types.dart'
;
import
'inline_span.dart'
;
import
'text_painter.dart'
;
import
'text_span.dart'
;
import
'text_style.dart'
;
/// An immutable placeholder that is embedded inline within text.
///
/// [PlaceholderSpan] represents a placeholder that acts as a stand-in for other
/// content. A [PlaceholderSpan] by itself does not contain useful
/// information to change a [TextSpan]. Instead, this class must be extended
/// to define contents.
///
/// [WidgetSpan] from the widgets library extends [PlaceholderSpan] and may be
/// used instead to specify a widget as the contents of the placeholder.
///
/// See also:
///
/// * [WidgetSpan], a leaf node that represents an embedded inline widget.
/// * [TextSpan], a node that represents text in a [TextSpan] tree.
/// * [Text], a widget for showing uniformly-styled text.
/// * [RichText], a widget for finer control of text rendering.
/// * [TextPainter], a class for painting [TextSpan] objects on a [Canvas].
abstract
class
PlaceholderSpan
extends
InlineSpan
{
/// Creates a [PlaceholderSpan] with the given values.
///
/// A [TextStyle] may be provided with the [style] property, but only the
/// decoration, foreground, background, and spacing options will be used.
const
PlaceholderSpan
({
this
.
alignment
=
ui
.
PlaceholderAlignment
.
bottom
,
this
.
baseline
,
TextStyle
style
,
})
:
super
(
style:
style
,);
/// How the placeholder aligns vertically with the text.
///
/// See [ui.PlaceholderAlignment] for details on each mode.
final
ui
.
PlaceholderAlignment
alignment
;
/// The [TextBaseline] to align against when using [ui.PlaceholderAlignment.baseline],
/// [ui.PlaceholderAlignment.aboveBaseline], and [ui.PlaceholderAlignment.belowBaseline].
///
/// This is ignored when using other alignment modes.
final
TextBaseline
baseline
;
/// [PlaceholderSpan]s are flattened to a `0xFFFC` object replacement character in the
/// plain text representation when `includePlaceholders` is true.
@override
void
computeToPlainText
(
StringBuffer
buffer
,
{
bool
includeSemanticsLabels
=
true
,
bool
includePlaceholders
=
true
})
{
if
(
includePlaceholders
)
{
buffer
.
write
(
'
\
uFFFC'
);
}
}
/// Populates the `semanticsOffsets` and `semanticsElements` with the appropriate data
/// to be able to construct a [SemanticsNode].
///
/// [PlaceholderSpan]s have a text length of 1, which corresponds to the object
/// replacement character (0xFFFC) that is inserted to represent it.
///
/// Null is added to `semanticsElements` for [PlaceholderSpan]s.
@override
void
describeSemantics
(
Accumulator
offset
,
List
<
int
>
semanticsOffsets
,
List
<
dynamic
>
semanticsElements
)
{
semanticsOffsets
.
add
(
offset
.
value
);
semanticsOffsets
.
add
(
offset
.
value
+
1
);
semanticsElements
.
add
(
null
);
// null indicates this is a placeholder.
offset
.
increment
(
1
);
}
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
properties
.
add
(
EnumProperty
<
ui
.
PlaceholderAlignment
>(
'alignment'
,
alignment
,
defaultValue:
null
));
properties
.
add
(
EnumProperty
<
TextBaseline
>(
'baseline'
,
baseline
,
defaultValue:
null
));
}
}
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/painting/text_painter.dart
View file @
4e5cf5ef
...
...
@@ -3,82 +3,18 @@
// found in the LICENSE file.
import
'dart:math'
show
min
,
max
;
import
'dart:ui'
as
ui
show
Paragraph
,
ParagraphBuilder
,
ParagraphConstraints
,
ParagraphStyle
,
PlaceholderAlignment
;
import
'dart:ui'
as
ui
show
Paragraph
,
ParagraphBuilder
,
ParagraphConstraints
,
ParagraphStyle
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/services.dart'
;
import
'basic_types.dart'
;
import
'inline_span.dart'
;
import
'placeholder_span.dart'
;
import
'strut_style.dart'
;
import
'text_span.dart'
;
export
'package:flutter/services.dart'
show
TextRange
,
TextSelection
;
/// Holds the [Size] and baseline required to represent the dimensions of
/// a placeholder in text.
///
/// Placeholders specify an empty space in the text layout, which is used
/// to later render arbitrary inline widgets into defined by a [WidgetSpan].
///
/// The [size] and [alignment] properties are required and cannot be null.
///
/// See also:
///
/// * [WidgetSpan], a subclass of [InlineSpan] and [PlaceholderSpan] that
/// represents an inline widget embedded within text. The space this
/// widget takes is indicated by a placeholder.
/// * [RichText], a text widget that supports text inline widgets.
@immutable
class
PlaceholderDimensions
{
/// Constructs a [PlaceholderDimensions] with the specified parameters.
///
/// The `size` and `alignment` are required as a placeholder's dimensions
/// require at least `size` and `alignment` to be fully defined.
const
PlaceholderDimensions
({
@required
this
.
size
,
@required
this
.
alignment
,
this
.
baseline
,
this
.
baselineOffset
,
})
:
assert
(
size
!=
null
),
assert
(
alignment
!=
null
);
/// Width and height dimensions of the placeholder.
final
Size
size
;
/// How to align the placeholder with the text.
///
/// See also:
///
/// * [baseline], the baseline to align to when using
/// [ui.PlaceholderAlignment.baseline],
/// [ui.PlaceholderAlignment.aboveBaseline],
/// or [ui.PlaceholderAlignment.underBaseline].
/// * [baselineOffset], the distance of the alphabetic baseline from the upper
/// edge of the placeholder.
final
ui
.
PlaceholderAlignment
alignment
;
/// Distance of the [baseline] from the upper edge of the placeholder.
///
/// Only used when [alignment] is [ui.PlaceholderAlignment.baseline].
final
double
baselineOffset
;
/// The [TextBaseline] to align to. Used with:
///
/// * [ui.PlaceholderAlignment.baseline]
/// * [ui.PlaceholderAlignment.aboveBaseline]
/// * [ui.PlaceholderAlignment.underBaseline]
/// * [ui.PlaceholderAlignment.middle]
final
TextBaseline
baseline
;
@override
String
toString
()
{
return
'PlaceholderDimensions(
$size
,
$baseline
)'
;
}
}
/// The different ways of considering the width of one or more lines of text.
///
/// See [Text.widthType].
...
...
@@ -94,9 +30,6 @@ enum TextWidthBasis {
longestLine
,
}
/// This is used to cache and pass the computed metrics regarding the
/// caret's size and position. This is preferred due to the expensive
/// nature of the calculation.
class
_CaretMetrics
{
const
_CaretMetrics
({
this
.
offset
,
this
.
fullHeight
});
/// The offset of the top left corner of the caret from the top left
...
...
@@ -134,7 +67,7 @@ class TextPainter {
///
/// The [maxLines] property, if non-null, must be greater than zero.
TextPainter
({
Inline
Span
text
,
Text
Span
text
,
TextAlign
textAlign
=
TextAlign
.
start
,
TextDirection
textDirection
,
double
textScaleFactor
=
1.0
,
...
...
@@ -166,9 +99,9 @@ class TextPainter {
/// After this is set, you must call [layout] before the next call to [paint].
///
/// This and [textDirection] must be non-null before you call [layout].
Inline
Span
get
text
=>
_text
;
Inline
Span
_text
;
set
text
(
Inline
Span
value
)
{
Text
Span
get
text
=>
_text
;
Text
Span
_text
;
set
text
(
Text
Span
value
)
{
assert
(
value
==
null
||
value
.
debugAssertIsValid
());
if
(
_text
==
value
)
return
;
...
...
@@ -333,53 +266,6 @@ class TextPainter {
ui
.
Paragraph
_layoutTemplate
;
/// An ordered list of [TextBox]es that bound the positions of the placeholders
/// in the paragraph.
///
/// Each box corresponds to a [PlaceholderSpan] in the order they were defined
/// in the [InlineSpan] tree.
List
<
TextBox
>
get
inlinePlaceholderBoxes
=>
_inlinePlaceholderBoxes
;
List
<
TextBox
>
_inlinePlaceholderBoxes
;
/// An ordered list of scales for each placeholder in the paragraph.
///
/// The scale is used as a multiplier on the height, width and baselineOffset of
/// the placeholder. Scale is primarily used to handle accessibility scaling.
///
/// Each scale corresponds to a [PlaceholderSpan] in the order they were defined
/// in the [InlineSpan] tree.
List
<
double
>
get
inlinePlaceholderScales
=>
_inlinePlaceholderScales
;
List
<
double
>
_inlinePlaceholderScales
;
/// Sets the dimensions of each placeholder in [text].
///
/// The number of [PlaceholderDimensions] provided should be the same as the
/// number of [PlaceholderSpan]s in text. Passing in an empty or null `value`
/// will do nothing.
///
/// If [layout] is attempted without setting the placeholder dimensions, the
/// placeholders will be ignored in the text layout and no valid
/// [inlinePlaceholderBoxes] will be returned.
void
setPlaceholderDimensions
(
List
<
PlaceholderDimensions
>
value
)
{
if
(
value
==
null
||
value
.
isEmpty
||
listEquals
(
value
,
_placeholderDimensions
))
{
return
;
}
assert
(()
{
int
placeholderCount
=
0
;
text
.
visitChildren
((
InlineSpan
span
)
{
if
(
span
is
PlaceholderSpan
)
{
placeholderCount
+=
1
;
}
return
true
;
});
return
placeholderCount
;
}()
==
value
.
length
);
_placeholderDimensions
=
value
;
_needsLayout
=
true
;
_paragraph
=
null
;
}
List
<
PlaceholderDimensions
>
_placeholderDimensions
;
ui
.
ParagraphStyle
_createParagraphStyle
([
TextDirection
defaultTextDirection
])
{
// The defaultTextDirection argument is used for preferredLineHeight in case
// textDirection hasn't yet been set.
...
...
@@ -533,8 +419,7 @@ class TextPainter {
_needsLayout
=
false
;
if
(
_paragraph
==
null
)
{
final
ui
.
ParagraphBuilder
builder
=
ui
.
ParagraphBuilder
(
_createParagraphStyle
());
_text
.
build
(
builder
,
textScaleFactor:
textScaleFactor
,
dimensions:
_placeholderDimensions
);
_inlinePlaceholderScales
=
builder
.
placeholderScales
;
_text
.
build
(
builder
,
textScaleFactor:
textScaleFactor
);
_paragraph
=
builder
.
build
();
}
_lastMinWidth
=
minWidth
;
...
...
@@ -542,11 +427,9 @@ class TextPainter {
_paragraph
.
layout
(
ui
.
ParagraphConstraints
(
width:
maxWidth
));
if
(
minWidth
!=
maxWidth
)
{
final
double
newWidth
=
maxIntrinsicWidth
.
clamp
(
minWidth
,
maxWidth
);
if
(
newWidth
!=
width
)
{
if
(
newWidth
!=
width
)
_paragraph
.
layout
(
ui
.
ParagraphConstraints
(
width:
newWidth
));
}
}
_inlinePlaceholderBoxes
=
_paragraph
.
getBoxesForPlaceholders
();
}
/// Paints the text onto the given canvas at the given offset.
...
...
@@ -608,7 +491,7 @@ class TextPainter {
// TODO(garyq): Use actual extended grapheme cluster length instead of
// an increasing cluster length amount to achieve deterministic performance.
Rect
_getRectFromUpstream
(
int
offset
,
Rect
caretPrototype
)
{
final
String
flattenedText
=
_text
.
toPlainText
(
includePlaceholders:
false
);
final
String
flattenedText
=
_text
.
toPlainText
();
final
int
prevCodeUnit
=
_text
.
codeUnitAt
(
max
(
0
,
offset
-
1
));
if
(
prevCodeUnit
==
null
)
return
null
;
...
...
@@ -624,12 +507,10 @@ class TextPainter {
if
(
boxes
.
isEmpty
)
{
// When we are at the beginning of the line, a non-surrogate position will
// return empty boxes. We break and try from downstream instead.
if
(!
needsSearch
)
{
if
(!
needsSearch
)
break
;
// Only perform one iteration if no search is required.
}
if
(
prevRuneOffset
<
-
flattenedText
.
length
)
{
if
(
prevRuneOffset
<
-
flattenedText
.
length
)
break
;
// Stop iterating when beyond the max length of the text.
}
// Multiply by two to log(n) time cover the entire text span. This allows
// faster discovery of very long clusters and reduces the possibility
// of certain large clusters taking much longer than others, which can
...
...
@@ -657,7 +538,7 @@ class TextPainter {
// TODO(garyq): Use actual extended grapheme cluster length instead of
// an increasing cluster length amount to achieve deterministic performance.
Rect
_getRectFromDownstream
(
int
offset
,
Rect
caretPrototype
)
{
final
String
flattenedText
=
_text
.
toPlainText
(
includePlaceholders:
false
);
final
String
flattenedText
=
_text
.
toPlainText
();
// We cap the offset at the final index of the _text.
final
int
nextCodeUnit
=
_text
.
codeUnitAt
(
min
(
offset
,
flattenedText
==
null
?
0
:
flattenedText
.
length
-
1
));
if
(
nextCodeUnit
==
null
)
...
...
@@ -673,12 +554,10 @@ class TextPainter {
if
(
boxes
.
isEmpty
)
{
// When we are at the end of the line, a non-surrogate position will
// return empty boxes. We break and try from upstream instead.
if
(!
needsSearch
)
{
if
(!
needsSearch
)
break
;
// Only perform one iteration if no search is required.
}
if
(
nextRuneOffset
>=
flattenedText
.
length
<<
1
)
{
if
(
nextRuneOffset
>=
flattenedText
.
length
<<
1
)
break
;
// Stop iterating when beyond the max length of the text.
}
// Multiply by two to log(n) time cover the entire text span. This allows
// faster discovery of very long clusters and reduces the possibility
// of certain large clusters taking much longer than others, which can
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/painting/text_span.dart
View file @
4e5cf5ef
...
...
@@ -9,8 +9,6 @@ import 'package:flutter/gestures.dart';
import
'package:flutter/services.dart'
;
import
'basic_types.dart'
;
import
'inline_span.dart'
;
import
'text_painter.dart'
;
import
'text_style.dart'
;
/// An immutable span of text.
...
...
@@ -23,9 +21,7 @@ import 'text_style.dart';
/// only partially) override the [style] of this object. If a
/// [TextSpan] has both [text] and [children], then the [text] is
/// treated as if it was an unstyled [TextSpan] at the start of the
/// [children] list. Leaving the [TextSpan.text] field null results
/// in the [TextSpan] acting as an empty node in the [InlineSpan]
/// tree with a list of children.
/// [children] list.
///
/// To paint a [TextSpan] on a [Canvas], use a [TextPainter]. To display a text
/// span in a widget, use a [RichText]. For text with a single style, consider
...
...
@@ -46,33 +42,27 @@ import 'text_style.dart';
/// _There is some more detailed sample code in the documentation for the
/// [recognizer] property._
///
/// The [TextSpan.text] will be used as the semantics label unless overriden
/// by the [TextSpan.semanticsLabel] property. Any [PlaceholderSpan]s in the
/// [TextSpan.children] list will separate the text before and after it into
/// two semantics nodes.
///
/// See also:
///
/// * [WidgetSpan], a leaf node that represents an embedded inline widget
/// in an [InlineSpan] tree. Specify a widget within the [children]
/// list by wrapping the widget with a [WidgetSpan]. The widget will be
/// laid out inline within the paragraph.
/// * [Text], a widget for showing uniformly-styled text.
/// * [RichText], a widget for finer control of text rendering.
/// * [TextPainter], a class for painting [TextSpan] objects on a [Canvas].
@immutable
class
TextSpan
extends
InlineSpan
{
class
TextSpan
extends
DiagnosticableTree
{
/// Creates a [TextSpan] with the given values.
///
/// For the object to be useful, at least one of [text] or
/// [children] should be set.
const
TextSpan
({
this
.
style
,
this
.
text
,
this
.
children
,
TextStyle
style
,
this
.
recognizer
,
this
.
semanticsLabel
,
})
:
super
(
style:
style
,);
});
/// The style to apply to the [text] and the [children].
final
TextStyle
style
;
/// The text contained in the span.
///
...
...
@@ -89,26 +79,26 @@ class TextSpan extends InlineSpan {
/// supported and may have unexpected results.
///
/// The list must not contain any nulls.
final
List
<
Inline
Span
>
children
;
final
List
<
Text
Span
>
children
;
/// A gesture recognizer that will receive events that hit this span.
/// A gesture recognizer that will receive events that hit this
text
span.
///
/// [
Inline
Span] itself does not implement hit testing or event dispatch. The
/// object that manages the [
Inline
Span] painting is also responsible for
/// [
Text
Span] itself does not implement hit testing or event dispatch. The
/// object that manages the [
Text
Span] painting is also responsible for
/// dispatching events. In the rendering library, that is the
/// [RenderParagraph] object, which corresponds to the [RichText] widget in
/// the widgets layer; these objects do not bubble events in [
Inline
Span]s, so a
/// the widgets layer; these objects do not bubble events in [
Text
Span]s, so a
/// [recognizer] is only effective for events that directly hit the [text] of
/// that [
Inline
Span], not any of its [children].
/// that [
Text
Span], not any of its [children].
///
/// [
Inline
Span] also does not manage the lifetime of the gesture recognizer.
/// [
Text
Span] also does not manage the lifetime of the gesture recognizer.
/// The code that owns the [GestureRecognizer] object must call
/// [GestureRecognizer.dispose] when the [
Inline
Span] object is no longer used.
/// [GestureRecognizer.dispose] when the [
Text
Span] object is no longer used.
///
/// {@tool sample}
///
/// This example shows how to manage the lifetime of a gesture recognizer
/// provided to a
n [Inline
Span] object. It defines a `BuzzingText` widget which
/// provided to a
[Text
Span] object. It defines a `BuzzingText` widget which
/// uses the [HapticFeedback] class to vibrate the device when the user
/// long-presses the "find the" span, which is underlined in wavy green. The
/// hit-testing is handled by the [RichText] widget.
...
...
@@ -141,11 +131,11 @@ class TextSpan extends InlineSpan {
///
/// @override
/// Widget build(BuildContext context) {
/// return
Text.rich
(
/// TextSpan(
/// return
RichText
(
///
text:
TextSpan(
/// text: 'Can you ',
/// style: TextStyle(color: Colors.black),
/// children: <
Inline
Span>[
/// children: <
Text
Span>[
/// TextSpan(
/// text: 'find the',
/// style: TextStyle(
...
...
@@ -167,7 +157,7 @@ class TextSpan extends InlineSpan {
/// {@end-tool}
final
GestureRecognizer
recognizer
;
/// An alternative semantics label for this
[TextSpan]
.
/// An alternative semantics label for this
text
.
///
/// If present, the semantics of this span will contain this value instead
/// of the actual text.
...
...
@@ -187,8 +177,7 @@ class TextSpan extends InlineSpan {
/// Rather than using this directly, it's simpler to use the
/// [TextPainter] class to paint [TextSpan] objects onto [Canvas]
/// objects.
@override
void
build
(
ui
.
ParagraphBuilder
builder
,
{
double
textScaleFactor
=
1.0
,
List
<
PlaceholderDimensions
>
dimensions
})
{
void
build
(
ui
.
ParagraphBuilder
builder
,
{
double
textScaleFactor
=
1.0
})
{
assert
(
debugAssertIsValid
());
final
bool
hasStyle
=
style
!=
null
;
if
(
hasStyle
)
...
...
@@ -196,9 +185,9 @@ class TextSpan extends InlineSpan {
if
(
text
!=
null
)
builder
.
addText
(
text
);
if
(
children
!=
null
)
{
for
(
Inline
Span
child
in
children
)
{
for
(
Text
Span
child
in
children
)
{
assert
(
child
!=
null
);
child
.
build
(
builder
,
textScaleFactor:
textScaleFactor
,
dimensions:
dimensions
);
child
.
build
(
builder
,
textScaleFactor:
textScaleFactor
);
}
}
if
(
hasStyle
)
...
...
@@ -207,15 +196,14 @@ class TextSpan extends InlineSpan {
/// Walks this text span and its descendants in pre-order and calls [visitor]
/// for each span that has text.
@override
bool
visitChildren
(
InlineSpanVisitor
visitor
)
{
bool
visitTextSpan
(
bool
visitor
(
TextSpan
span
))
{
if
(
text
!=
null
)
{
if
(!
visitor
(
this
))
return
false
;
}
if
(
children
!=
null
)
{
for
(
Inline
Span
child
in
children
)
{
if
(!
child
.
visit
Childre
n
(
visitor
))
for
(
Text
Span
child
in
children
)
{
if
(!
child
.
visit
TextSpa
n
(
visitor
))
return
false
;
}
}
...
...
@@ -223,62 +211,63 @@ class TextSpan extends InlineSpan {
}
/// Returns the text span that contains the given position in the text.
@override
InlineSpan
getSpanForPositionVisitor
(
TextPosition
position
,
Accumulator
offset
)
{
if
(
text
==
null
)
{
return
null
;
}
TextSpan
getSpanForPosition
(
TextPosition
position
)
{
assert
(
debugAssertIsValid
());
final
TextAffinity
affinity
=
position
.
affinity
;
final
int
targetOffset
=
position
.
offset
;
final
int
endOffset
=
offset
.
value
+
text
.
length
;
if
(
offset
.
value
==
targetOffset
&&
affinity
==
TextAffinity
.
downstream
||
offset
.
value
<
targetOffset
&&
targetOffset
<
endOffset
||
endOffset
==
targetOffset
&&
affinity
==
TextAffinity
.
upstream
)
{
return
this
;
}
offset
.
increment
(
text
.
length
);
return
null
;
int
offset
=
0
;
TextSpan
result
;
visitTextSpan
((
TextSpan
span
)
{
assert
(
result
==
null
);
final
int
endOffset
=
offset
+
span
.
text
.
length
;
if
(
targetOffset
==
offset
&&
affinity
==
TextAffinity
.
downstream
||
targetOffset
>
offset
&&
targetOffset
<
endOffset
||
targetOffset
==
endOffset
&&
affinity
==
TextAffinity
.
upstream
)
{
result
=
span
;
return
false
;
}
offset
=
endOffset
;
return
true
;
});
return
result
;
}
@override
void
computeToPlainText
(
StringBuffer
buffer
,
{
bool
includeSemanticsLabels
=
true
,
bool
includePlaceholders
=
true
})
{
/// Flattens the [TextSpan] tree into a single string.
///
/// Styles are not honored in this process. If `includeSemanticsLabels` is
/// true, then the text returned will include the [semanticsLabel]s instead of
/// the text contents when they are present.
String
toPlainText
({
bool
includeSemanticsLabels
=
true
})
{
assert
(
debugAssertIsValid
());
if
(
semanticsLabel
!=
null
&&
includeSemanticsLabels
)
{
buffer
.
write
(
semanticsLabel
);
}
else
if
(
text
!=
null
)
{
buffer
.
write
(
text
);
}
if
(
children
!=
null
)
{
for
(
InlineSpan
child
in
children
)
{
child
.
computeToPlainText
(
buffer
,
includeSemanticsLabels:
includeSemanticsLabels
,
includePlaceholders:
includePlaceholders
,
);
final
StringBuffer
buffer
=
StringBuffer
();
visitTextSpan
((
TextSpan
span
)
{
if
(
span
.
semanticsLabel
!=
null
&&
includeSemanticsLabels
)
{
buffer
.
write
(
span
.
semanticsLabel
);
}
else
{
buffer
.
write
(
span
.
text
);
}
}
return
true
;
});
return
buffer
.
toString
();
}
@override
int
codeUnitAtVisitor
(
int
index
,
Accumulator
offset
)
{
if
(
text
==
null
)
{
/// Returns the UTF-16 code unit at the given index in the flattened string.
///
/// Returns null if the index is out of bounds.
int
codeUnitAt
(
int
index
)
{
if
(
index
<
0
)
return
null
;
}
if
(
index
-
offset
.
value
<
text
.
length
)
{
return
text
.
codeUnitAt
(
index
-
offset
.
value
);
}
offset
.
increment
(
text
.
length
);
return
null
;
}
@override
void
describeSemantics
(
Accumulator
offset
,
List
<
int
>
semanticsOffsets
,
List
<
dynamic
>
semanticsElements
)
{
if
(
recognizer
!=
null
&&
(
recognizer
is
TapGestureRecognizer
||
recognizer
is
LongPressGestureRecognizer
))
{
final
int
length
=
semanticsLabel
?.
length
??
text
.
length
;
semanticsOffsets
.
add
(
offset
.
value
);
semanticsOffsets
.
add
(
offset
.
value
+
length
);
semanticsElements
.
add
(
recognizer
);
}
offset
.
increment
(
text
!=
null
?
text
.
length
:
0
);
int
offset
=
0
;
int
result
;
visitTextSpan
((
TextSpan
span
)
{
if
(
index
-
offset
<
span
.
text
.
length
)
{
result
=
span
.
text
.
codeUnitAt
(
index
-
offset
);
return
false
;
}
offset
+=
span
.
text
.
length
;
return
true
;
});
return
result
;
}
/// In checked mode, throws an exception if the object is not in a
...
...
@@ -289,39 +278,45 @@ class TextSpan extends InlineSpan {
/// ```dart
/// assert(myTextSpan.debugAssertIsValid());
/// ```
@override
bool
debugAssertIsValid
()
{
assert
(()
{
if
(
children
!=
null
)
{
for
(
InlineSpan
child
in
children
)
{
assert
(
child
!=
null
,
'TextSpan contains a null child.
\n
...'
'A TextSpan object with a non-null child list should not have any nulls in its child list.
\n
'
'The full text in question was:
\n
'
'
${toStringDeep(prefixLineOne: ' ')}
'
);
assert
(
child
.
debugAssertIsValid
());
if
(!
visitTextSpan
((
TextSpan
span
)
{
if
(
span
.
children
!=
null
)
{
for
(
TextSpan
child
in
span
.
children
)
{
if
(
child
==
null
)
return
false
;
}
}
return
true
;
}))
{
throw
FlutterError
(
'TextSpan contains a null child.
\n
'
'A TextSpan object with a non-null child list should not have any nulls in its child list.
\n
'
'The full text in question was:
\n
'
'
${toStringDeep(prefixLineOne: ' ')}
'
);
}
return
true
;
}());
return
super
.
debugAssertIsValid
()
;
return
true
;
}
@override
RenderComparison
compareTo
(
InlineSpan
other
)
{
/// Describe the difference between this text span and another, in terms of
/// how much damage it will make to the rendering. The comparison is deep.
///
/// See also:
///
/// * [TextStyle.compareTo], which does the same thing for [TextStyle]s.
RenderComparison
compareTo
(
TextSpan
other
)
{
if
(
identical
(
this
,
other
))
return
RenderComparison
.
identical
;
if
(
other
.
runtimeType
!=
runtimeType
)
return
RenderComparison
.
layout
;
final
TextSpan
textSpan
=
other
;
if
(
textSpan
.
text
!=
text
||
children
?.
length
!=
textSpan
.
children
?.
length
||
(
style
==
null
)
!=
(
textSpan
.
style
==
null
))
if
(
other
.
text
!=
text
||
children
?.
length
!=
other
.
children
?.
length
||
(
style
==
null
)
!=
(
other
.
style
==
null
))
return
RenderComparison
.
layout
;
RenderComparison
result
=
recognizer
==
textSpan
.
recognizer
?
RenderComparison
.
identical
:
RenderComparison
.
metadata
;
RenderComparison
result
=
recognizer
==
other
.
recognizer
?
RenderComparison
.
identical
:
RenderComparison
.
metadata
;
if
(
style
!=
null
)
{
final
RenderComparison
candidate
=
style
.
compareTo
(
textSpan
.
style
);
final
RenderComparison
candidate
=
style
.
compareTo
(
other
.
style
);
if
(
candidate
.
index
>
result
.
index
)
result
=
candidate
;
if
(
result
==
RenderComparison
.
layout
)
...
...
@@ -329,7 +324,7 @@ class TextSpan extends InlineSpan {
}
if
(
children
!=
null
)
{
for
(
int
index
=
0
;
index
<
children
.
length
;
index
+=
1
)
{
final
RenderComparison
candidate
=
children
[
index
].
compareTo
(
textSpan
.
children
[
index
]);
final
RenderComparison
candidate
=
children
[
index
].
compareTo
(
other
.
children
[
index
]);
if
(
candidate
.
index
>
result
.
index
)
result
=
candidate
;
if
(
result
==
RenderComparison
.
layout
)
...
...
@@ -345,17 +340,16 @@ class TextSpan extends InlineSpan {
return
true
;
if
(
other
.
runtimeType
!=
runtimeType
)
return
false
;
if
(
super
!=
other
)
return
false
;
final
TextSpan
typedOther
=
other
;
return
typedOther
.
text
==
text
&&
typedOther
.
style
==
style
&&
typedOther
.
recognizer
==
recognizer
&&
typedOther
.
semanticsLabel
==
semanticsLabel
&&
listEquals
<
Inline
Span
>(
typedOther
.
children
,
children
);
&&
listEquals
<
Text
Span
>(
typedOther
.
children
,
children
);
}
@override
int
get
hashCode
=>
hashValues
(
s
uper
.
hashCod
e
,
text
,
recognizer
,
semanticsLabel
,
hashList
(
children
));
int
get
hashCode
=>
hashValues
(
s
tyl
e
,
text
,
recognizer
,
semanticsLabel
,
hashList
(
children
));
@override
String
toStringShort
()
=>
'
$runtimeType
'
;
...
...
@@ -363,10 +357,11 @@ class TextSpan extends InlineSpan {
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
properties
.
add
(
StringProperty
(
'text'
,
text
,
showName:
false
,
defaultValue:
null
));
if
(
style
==
null
&&
text
==
null
&&
children
==
null
)
properties
.
add
(
DiagnosticsNode
.
message
(
'(empty)'
));
properties
.
defaultDiagnosticsTreeStyle
=
DiagnosticsTreeStyle
.
whitespace
;
// Properties on style are added as if they were properties directly on
// this TextSpan.
if
(
style
!=
null
)
style
.
debugFillProperties
(
properties
);
properties
.
add
(
DiagnosticsProperty
<
GestureRecognizer
>(
'recognizer'
,
recognizer
,
...
...
@@ -374,16 +369,22 @@ class TextSpan extends InlineSpan {
defaultValue:
null
,
));
if
(
semanticsLabel
!=
null
)
{
properties
.
add
(
StringProperty
(
'semanticsLabel'
,
semanticsLabel
));
}
properties
.
add
(
StringProperty
(
'text'
,
text
,
showName:
false
,
defaultValue:
null
));
if
(
style
==
null
&&
text
==
null
&&
children
==
null
)
properties
.
add
(
DiagnosticsNode
.
message
(
'(empty)'
));
}
@override
List
<
DiagnosticsNode
>
debugDescribeChildren
()
{
if
(
children
==
null
)
return
const
<
DiagnosticsNode
>[];
return
children
.
map
<
DiagnosticsNode
>((
Inline
Span
child
)
{
return
children
.
map
<
DiagnosticsNode
>((
Text
Span
child
)
{
if
(
child
!=
null
)
{
return
child
.
toDiagnosticsNode
();
}
else
{
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/rendering/box.dart
View file @
4e5cf5ef
...
...
@@ -1728,10 +1728,7 @@ abstract class RenderBox extends RenderObject {
return
true
;
}());
_size
=
value
;
assert
(()
{
debugAssertDoesMeetConstraints
();
return
true
;
}());
assert
(()
{
debugAssertDoesMeetConstraints
();
return
true
;
}());
}
/// Claims ownership of the given [Size].
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/rendering/debug_overflow_indicator.dart
View file @
4e5cf5ef
...
...
@@ -284,8 +284,8 @@ mixin DebugOverflowIndicatorMixin on RenderObject {
final
List
<
_OverflowRegionData
>
overflowRegions
=
_calculateOverflowRegions
(
overflow
,
containerRect
);
for
(
_OverflowRegionData
region
in
overflowRegions
)
{
context
.
canvas
.
drawRect
(
region
.
rect
.
shift
(
offset
),
_indicatorPaint
);
final
TextSpan
textSpan
=
_indicatorLabel
[
region
.
side
.
index
].
text
;
if
(
textSpan
?.
text
!=
region
.
label
)
{
if
(
_indicatorLabel
[
region
.
side
.
index
].
text
?.
text
!=
region
.
label
)
{
_indicatorLabel
[
region
.
side
.
index
].
text
=
TextSpan
(
text:
region
.
label
,
style:
_indicatorTextStyle
,
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/rendering/paragraph.dart
View file @
4e5cf5ef
...
...
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:ui'
as
ui
show
Gradient
,
Shader
,
TextBox
,
PlaceholderAlignment
;
import
'dart:ui'
as
ui
show
Gradient
,
Shader
,
TextBox
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
...
...
@@ -10,7 +10,6 @@ import 'package:flutter/painting.dart';
import
'package:flutter/semantics.dart'
;
import
'package:flutter/services.dart'
;
import
'package:vector_math/vector_math_64.dart'
;
import
'box.dart'
;
import
'debug.dart'
;
...
...
@@ -36,27 +35,8 @@ enum TextOverflow {
const
String
_kEllipsis
=
'
\
u2026'
;
/// Parent data for use with [RenderParagraph].
class
TextParentData
extends
ContainerBoxParentData
<
RenderBox
>
{
/// The scaling of the text.
double
scale
;
@override
String
toString
()
{
final
List
<
String
>
values
=
<
String
>[];
if
(
offset
!=
null
)
values
.
add
(
'offset=
$offset
'
);
if
(
scale
!=
null
)
values
.
add
(
'scale=
$scale
'
);
values
.
add
(
super
.
toString
());
return
values
.
join
(
'; '
);
}
}
/// A render object that displays a paragraph of text.
class
RenderParagraph
extends
RenderBox
with
ContainerRenderObjectMixin
<
RenderBox
,
TextParentData
>,
RenderBoxContainerDefaultsMixin
<
RenderBox
,
TextParentData
>
{
/// A render object that displays a paragraph of text
class
RenderParagraph
extends
RenderBox
{
/// Creates a paragraph render object.
///
/// The [text], [textAlign], [textDirection], [overflow], [softWrap], and
...
...
@@ -64,7 +44,8 @@ class RenderParagraph extends RenderBox
///
/// The [maxLines] property may be null (and indeed defaults to null), but if
/// it is not null, it must be greater than zero.
RenderParagraph
(
InlineSpan
text
,
{
RenderParagraph
(
TextSpan
text
,
{
TextAlign
textAlign
=
TextAlign
.
start
,
@required
TextDirection
textDirection
,
bool
softWrap
=
true
,
...
...
@@ -74,7 +55,6 @@ class RenderParagraph extends RenderBox
TextWidthBasis
textWidthBasis
=
TextWidthBasis
.
parent
,
Locale
locale
,
StrutStyle
strutStyle
,
List
<
RenderBox
>
children
,
})
:
assert
(
text
!=
null
),
assert
(
text
.
debugAssertIsValid
()),
assert
(
textAlign
!=
null
),
...
...
@@ -96,22 +76,13 @@ class RenderParagraph extends RenderBox
locale:
locale
,
strutStyle:
strutStyle
,
textWidthBasis:
textWidthBasis
,
)
{
addAll
(
children
);
_extractPlaceholderSpans
(
text
);
}
@override
void
setupParentData
(
RenderBox
child
)
{
if
(
child
.
parentData
is
!
TextParentData
)
child
.
parentData
=
TextParentData
();
}
);
final
TextPainter
_textPainter
;
/// The text to display
Inline
Span
get
text
=>
_textPainter
.
text
;
set
text
(
Inline
Span
value
)
{
Text
Span
get
text
=>
_textPainter
.
text
;
set
text
(
Text
Span
value
)
{
assert
(
value
!=
null
);
switch
(
_textPainter
.
text
.
compareTo
(
value
))
{
case
RenderComparison
.
identical
:
...
...
@@ -119,31 +90,17 @@ class RenderParagraph extends RenderBox
return
;
case
RenderComparison
.
paint
:
_textPainter
.
text
=
value
;
_extractPlaceholderSpans
(
value
);
markNeedsPaint
();
markNeedsSemanticsUpdate
();
break
;
case
RenderComparison
.
layout
:
_textPainter
.
text
=
value
;
_overflowShader
=
null
;
_extractPlaceholderSpans
(
value
);
markNeedsLayout
();
break
;
}
}
List
<
PlaceholderSpan
>
_placeholderSpans
;
void
_extractPlaceholderSpans
(
InlineSpan
span
)
{
_placeholderSpans
=
<
PlaceholderSpan
>[];
span
.
visitChildren
((
InlineSpan
span
)
{
if
(
span
is
PlaceholderSpan
)
{
final
PlaceholderSpan
placeholderSpan
=
span
;
_placeholderSpans
.
add
(
placeholderSpan
);
}
return
true
;
});
}
/// How the text should be aligned horizontally.
TextAlign
get
textAlign
=>
_textPainter
.
textAlign
;
set
textAlign
(
TextAlign
value
)
{
...
...
@@ -272,31 +229,28 @@ class RenderParagraph extends RenderBox
markNeedsLayout
();
}
void
_layoutText
({
double
minWidth
=
0.0
,
double
maxWidth
=
double
.
infinity
})
{
final
bool
widthMatters
=
softWrap
||
overflow
==
TextOverflow
.
ellipsis
;
_textPainter
.
layout
(
minWidth:
minWidth
,
maxWidth:
widthMatters
?
maxWidth
:
double
.
infinity
);
}
void
_layoutTextWithConstraints
(
BoxConstraints
constraints
)
{
_layoutText
(
minWidth:
constraints
.
minWidth
,
maxWidth:
constraints
.
maxWidth
);
}
@override
double
computeMinIntrinsicWidth
(
double
height
)
{
if
(!
_canComputeIntrinsics
())
{
return
0.0
;
}
_computeChildrenWidthWithMinIntrinsics
(
height
);
_layoutText
();
// layout with infinite width.
_layoutText
();
return
_textPainter
.
minIntrinsicWidth
;
}
@override
double
computeMaxIntrinsicWidth
(
double
height
)
{
if
(!
_canComputeIntrinsics
())
{
return
0.0
;
}
_computeChildrenWidthWithMaxIntrinsics
(
height
);
_layoutText
();
// layout with infinite width.
_layoutText
();
return
_textPainter
.
maxIntrinsicWidth
;
}
double
_computeIntrinsicHeight
(
double
width
)
{
if
(!
_canComputeIntrinsics
())
{
return
0.0
;
}
_computeChildrenHeightWithMinIntrinsics
(
width
);
_layoutText
(
minWidth:
width
,
maxWidth:
width
);
return
_textPainter
.
height
;
}
...
...
@@ -320,114 +274,9 @@ class RenderParagraph extends RenderBox
return
_textPainter
.
computeDistanceToActualBaseline
(
baseline
);
}
// Intrinsics cannot be calculated without a full layout for
// alignments that require the baseline (baseline, aboveBaseline,
// belowBaseline).
bool
_canComputeIntrinsics
()
{
for
(
PlaceholderSpan
span
in
_placeholderSpans
)
{
switch
(
span
.
alignment
)
{
case
ui
.
PlaceholderAlignment
.
baseline
:
case
ui
.
PlaceholderAlignment
.
aboveBaseline
:
case
ui
.
PlaceholderAlignment
.
belowBaseline
:
{
assert
(
RenderObject
.
debugCheckingIntrinsics
,
'Intrinsics are not available for PlaceholderAlignment.baseline, '
'PlaceholderAlignment.aboveBaseline, or PlaceholderAlignment.belowBaseline,'
);
return
false
;
}
case
ui
.
PlaceholderAlignment
.
top
:
case
ui
.
PlaceholderAlignment
.
middle
:
case
ui
.
PlaceholderAlignment
.
bottom
:
{
continue
;
}
}
}
return
true
;
}
void
_computeChildrenWidthWithMaxIntrinsics
(
double
height
)
{
RenderBox
child
=
firstChild
;
final
List
<
PlaceholderDimensions
>
placeholderDimensions
=
List
<
PlaceholderDimensions
>(
childCount
);
int
childIndex
=
0
;
while
(
child
!=
null
)
{
// Height and baseline is irrelevant as all text will be laid
// out in a single line.
placeholderDimensions
[
childIndex
]
=
PlaceholderDimensions
(
size:
Size
(
child
.
getMaxIntrinsicWidth
(
height
),
height
),
alignment:
_placeholderSpans
[
childIndex
].
alignment
,
baseline:
_placeholderSpans
[
childIndex
].
baseline
,
);
child
=
childAfter
(
child
);
childIndex
+=
1
;
}
_textPainter
.
setPlaceholderDimensions
(
placeholderDimensions
);
}
void
_computeChildrenWidthWithMinIntrinsics
(
double
height
)
{
RenderBox
child
=
firstChild
;
final
List
<
PlaceholderDimensions
>
placeholderDimensions
=
List
<
PlaceholderDimensions
>(
childCount
);
int
childIndex
=
0
;
while
(
child
!=
null
)
{
final
double
intrinsicWidth
=
child
.
getMinIntrinsicWidth
(
height
);
final
double
intrinsicHeight
=
child
.
getMinIntrinsicHeight
(
intrinsicWidth
);
placeholderDimensions
[
childIndex
]
=
PlaceholderDimensions
(
size:
Size
(
intrinsicWidth
,
intrinsicHeight
),
alignment:
_placeholderSpans
[
childIndex
].
alignment
,
baseline:
_placeholderSpans
[
childIndex
].
baseline
,
);
child
=
childAfter
(
child
);
childIndex
+=
1
;
}
_textPainter
.
setPlaceholderDimensions
(
placeholderDimensions
);
}
void
_computeChildrenHeightWithMinIntrinsics
(
double
width
)
{
RenderBox
child
=
firstChild
;
final
List
<
PlaceholderDimensions
>
placeholderDimensions
=
List
<
PlaceholderDimensions
>(
childCount
);
int
childIndex
=
0
;
while
(
child
!=
null
)
{
final
double
intrinsicHeight
=
child
.
getMinIntrinsicHeight
(
width
);
final
double
intrinsicWidth
=
child
.
getMinIntrinsicWidth
(
intrinsicHeight
);
placeholderDimensions
[
childIndex
]
=
PlaceholderDimensions
(
size:
Size
(
intrinsicWidth
,
intrinsicHeight
),
alignment:
_placeholderSpans
[
childIndex
].
alignment
,
baseline:
_placeholderSpans
[
childIndex
].
baseline
,
);
child
=
childAfter
(
child
);
childIndex
+=
1
;
}
_textPainter
.
setPlaceholderDimensions
(
placeholderDimensions
);
}
@override
bool
hitTestSelf
(
Offset
position
)
=>
true
;
@override
bool
hitTestChildren
(
BoxHitTestResult
result
,
{
Offset
position
})
{
RenderBox
child
=
firstChild
;
while
(
child
!=
null
)
{
final
TextParentData
textParentData
=
child
.
parentData
;
final
Matrix4
transform
=
Matrix4
.
translationValues
(
textParentData
.
offset
.
dx
,
textParentData
.
offset
.
dy
,
0.0
)
..
scale
(
textParentData
.
scale
,
textParentData
.
scale
,
textParentData
.
scale
);
final
bool
isHit
=
result
.
addWithPaintTransform
(
transform:
transform
,
position:
position
,
hitTest:
(
BoxHitTestResult
result
,
Offset
transformed
)
{
assert
(()
{
final
Offset
manualPosition
=
(
position
-
textParentData
.
offset
)
/
textParentData
.
scale
;
return
(
transformed
.
dx
-
manualPosition
.
dx
).
abs
()
<
precisionErrorTolerance
&&
(
transformed
.
dy
-
manualPosition
.
dy
).
abs
()
<
precisionErrorTolerance
;
}());
return
child
.
hitTest
(
result
,
position:
transformed
);
},
);
if
(
isHit
)
{
return
true
;
}
child
=
childAfter
(
child
);
}
return
false
;
}
@override
void
handleEvent
(
PointerEvent
event
,
BoxHitTestEntry
entry
)
{
assert
(
debugHandleEvent
(
event
,
entry
));
...
...
@@ -450,81 +299,9 @@ class RenderParagraph extends RenderBox
@visibleForTesting
bool
get
debugHasOverflowShader
=>
_overflowShader
!=
null
;
void
_layoutText
({
double
minWidth
=
0.0
,
double
maxWidth
=
double
.
infinity
})
{
final
bool
widthMatters
=
softWrap
||
overflow
==
TextOverflow
.
ellipsis
;
_textPainter
.
layout
(
minWidth:
minWidth
,
maxWidth:
widthMatters
?
maxWidth
:
double
.
infinity
);
}
void
_layoutTextWithConstraints
(
BoxConstraints
constraints
)
{
_layoutText
(
minWidth:
constraints
.
minWidth
,
maxWidth:
constraints
.
maxWidth
);
}
// Layout the child inline widgets. We then pass the dimensions of the
// children to _textPainter so that appropriate placeholders can be inserted
// into the LibTxt layout. This does not do anything if no inline widgets were
// specified.
void
_layoutChildren
(
BoxConstraints
constraints
)
{
if
(
childCount
==
0
)
{
return
;
}
RenderBox
child
=
firstChild
;
final
List
<
PlaceholderDimensions
>
placeholderDimensions
=
List
<
PlaceholderDimensions
>(
childCount
);
int
childIndex
=
0
;
while
(
child
!=
null
)
{
// Only constrain the width to the maximum width of the paragraph.
// Leave height unconstrained, which will overflow if expanded past.
child
.
layout
(
BoxConstraints
(
maxWidth:
constraints
.
maxWidth
,
),
parentUsesSize:
true
);
double
baselineOffset
;
switch
(
_placeholderSpans
[
childIndex
].
alignment
)
{
case
ui
.
PlaceholderAlignment
.
baseline
:
{
baselineOffset
=
child
.
getDistanceToBaseline
(
_placeholderSpans
[
childIndex
].
baseline
);
break
;
}
default
:
{
baselineOffset
=
null
;
break
;
}
}
placeholderDimensions
[
childIndex
]
=
PlaceholderDimensions
(
size:
child
.
size
,
alignment:
_placeholderSpans
[
childIndex
].
alignment
,
baseline:
_placeholderSpans
[
childIndex
].
baseline
,
baselineOffset:
baselineOffset
,
);
child
=
childAfter
(
child
);
childIndex
+=
1
;
}
_textPainter
.
setPlaceholderDimensions
(
placeholderDimensions
);
}
// Iterate through the laid-out children and set the parentData offsets based
// off of the placeholders inserted for each child.
void
_setParentData
()
{
RenderBox
child
=
firstChild
;
int
childIndex
=
0
;
while
(
child
!=
null
)
{
final
TextParentData
textParentData
=
child
.
parentData
;
textParentData
.
offset
=
Offset
(
_textPainter
.
inlinePlaceholderBoxes
[
childIndex
].
left
,
_textPainter
.
inlinePlaceholderBoxes
[
childIndex
].
top
);
textParentData
.
scale
=
_textPainter
.
inlinePlaceholderScales
[
childIndex
];
child
=
childAfter
(
child
);
childIndex
+=
1
;
}
}
@override
void
performLayout
()
{
_layoutChildren
(
constraints
);
_layoutTextWithConstraints
(
constraints
);
_setParentData
();
// We grab _textPainter.size and _textPainter.didExceedMaxLines here because
// assigning to `size` will trigger us to validate our intrinsic sizes,
// which will change _textPainter's layout because the intrinsic size
...
...
@@ -609,12 +386,13 @@ class RenderParagraph extends RenderBox
// If you remove this call, make sure that changing the textAlign still
// works properly.
_layoutTextWithConstraints
(
constraints
);
final
Canvas
canvas
=
context
.
canvas
;
assert
(()
{
if
(
debugRepaintTextRainbowEnabled
)
{
final
Paint
paint
=
Paint
()
..
color
=
debugCurrentRepaintColor
.
toColor
();
c
ontext
.
c
anvas
.
drawRect
(
offset
&
size
,
paint
);
canvas
.
drawRect
(
offset
&
size
,
paint
);
}
return
true
;
}());
...
...
@@ -624,44 +402,22 @@ class RenderParagraph extends RenderBox
if
(
_overflowShader
!=
null
)
{
// This layer limits what the shader below blends with to be just the text
// (as opposed to the text and its background).
c
ontext
.
c
anvas
.
saveLayer
(
bounds
,
Paint
());
canvas
.
saveLayer
(
bounds
,
Paint
());
}
else
{
c
ontext
.
c
anvas
.
save
();
canvas
.
save
();
}
context
.
canvas
.
clipRect
(
bounds
);
}
_textPainter
.
paint
(
context
.
canvas
,
offset
);
RenderBox
child
=
firstChild
;
int
childIndex
=
0
;
while
(
child
!=
null
)
{
assert
(
childIndex
<
_textPainter
.
inlinePlaceholderBoxes
.
length
);
final
TextParentData
textParentData
=
child
.
parentData
;
final
double
scale
=
textParentData
.
scale
;
context
.
pushTransform
(
needsCompositing
,
offset
+
textParentData
.
offset
,
Matrix4
.
diagonal3Values
(
scale
,
scale
,
scale
),
(
PaintingContext
context
,
Offset
offset
)
{
context
.
paintChild
(
child
,
offset
,
);
},
);
child
=
childAfter
(
child
);
childIndex
+=
1
;
canvas
.
clipRect
(
bounds
);
}
_textPainter
.
paint
(
canvas
,
offset
);
if
(
_needsClipping
)
{
if
(
_overflowShader
!=
null
)
{
c
ontext
.
c
anvas
.
translate
(
offset
.
dx
,
offset
.
dy
);
canvas
.
translate
(
offset
.
dx
,
offset
.
dy
);
final
Paint
paint
=
Paint
()
..
blendMode
=
BlendMode
.
modulate
..
shader
=
_overflowShader
;
c
ontext
.
c
anvas
.
drawRect
(
Offset
.
zero
&
size
,
paint
);
canvas
.
drawRect
(
Offset
.
zero
&
size
,
paint
);
}
c
ontext
.
c
anvas
.
restore
();
canvas
.
restore
();
}
}
...
...
@@ -725,23 +481,26 @@ class RenderParagraph extends RenderBox
return
_textPainter
.
size
;
}
// The offsets for each span that requires custom semantics.
final
List
<
int
>
_inlineSemanticsOffsets
=
<
int
>[];
// Holds either [GestureRecognizer] or null (for placeholders) to generate
// proper semnatics configurations.
final
List
<
dynamic
>
_inlineSemanticsElements
=
<
dynamic
>[];
final
List
<
int
>
_recognizerOffsets
=
<
int
>[];
final
List
<
GestureRecognizer
>
_recognizers
=
<
GestureRecognizer
>[];
@override
void
describeSemanticsConfiguration
(
SemanticsConfiguration
config
)
{
super
.
describeSemanticsConfiguration
(
config
);
_inlineSemanticsOffsets
.
clear
();
_inlineSemanticsElements
.
clear
();
final
Accumulator
offset
=
Accumulator
();
text
.
visitChildren
((
InlineSpan
span
)
{
span
.
describeSemantics
(
offset
,
_inlineSemanticsOffsets
,
_inlineSemanticsElements
);
_recognizerOffsets
.
clear
();
_recognizers
.
clear
();
int
offset
=
0
;
text
.
visitTextSpan
((
TextSpan
span
)
{
if
(
span
.
recognizer
!=
null
&&
(
span
.
recognizer
is
TapGestureRecognizer
||
span
.
recognizer
is
LongPressGestureRecognizer
))
{
final
int
length
=
span
.
semanticsLabel
?.
length
??
span
.
text
.
length
;
_recognizerOffsets
.
add
(
offset
);
_recognizerOffsets
.
add
(
offset
+
length
);
_recognizers
.
add
(
span
.
recognizer
);
}
offset
+=
span
.
text
.
length
;
return
true
;
});
if
(
_
inlineSemantics
Offsets
.
isNotEmpty
)
{
if
(
_
recognizer
Offsets
.
isNotEmpty
)
{
config
.
explicitChildNodes
=
true
;
config
.
isSemanticBoundary
=
true
;
}
else
{
...
...
@@ -752,9 +511,10 @@ class RenderParagraph extends RenderBox
@override
void
assembleSemanticsNode
(
SemanticsNode
node
,
SemanticsConfiguration
config
,
Iterable
<
SemanticsNode
>
children
)
{
assert
(
_inlineSemanticsOffsets
.
isNotEmpty
);
assert
(
_inlineSemanticsOffsets
.
length
.
isEven
);
assert
(
_inlineSemanticsElements
.
isNotEmpty
);
assert
(
_recognizerOffsets
.
isNotEmpty
);
assert
(
_recognizerOffsets
.
length
.
isEven
);
assert
(
_recognizers
.
isNotEmpty
);
assert
(
children
.
isEmpty
);
final
List
<
SemanticsNode
>
newChildren
=
<
SemanticsNode
>[];
final
String
rawLabel
=
text
.
toPlainText
();
int
current
=
0
;
...
...
@@ -762,7 +522,7 @@ class RenderParagraph extends RenderBox
TextDirection
currentDirection
=
textDirection
;
Rect
currentRect
;
SemanticsConfiguration
buildSemanticsConfig
(
int
start
,
int
end
,
{
bool
includeText
=
true
}
)
{
SemanticsConfiguration
buildSemanticsConfig
(
int
start
,
int
end
)
{
final
TextDirection
initialDirection
=
currentDirection
;
final
TextSelection
selection
=
TextSelection
(
baseOffset:
start
,
extentOffset:
end
);
final
List
<
ui
.
TextBox
>
rects
=
getBoxesForSelection
(
selection
);
...
...
@@ -782,21 +542,15 @@ class RenderParagraph extends RenderBox
rect
.
bottom
.
ceilToDouble
()
+
4.0
,
);
order
+=
1
;
final
SemanticsConfiguration
configuration
=
SemanticsConfiguration
()
return
SemanticsConfiguration
()
..
sortKey
=
OrdinalSortKey
(
order
)
..
textDirection
=
initialDirection
;
if
(
includeText
)
{
configuration
.
label
=
rawLabel
.
substring
(
start
,
end
);
}
return
configuration
;
..
textDirection
=
initialDirection
..
label
=
rawLabel
.
substring
(
start
,
end
);
}
int
childIndex
=
0
;
RenderBox
child
=
firstChild
;
for
(
int
i
=
0
,
j
=
0
;
i
<
_inlineSemanticsOffsets
.
length
;
i
+=
2
,
j
++)
{
final
int
start
=
_inlineSemanticsOffsets
[
i
];
final
int
end
=
_inlineSemanticsOffsets
[
i
+
1
];
// Add semantics for any text between the previous recognizer/widget and this one.
for
(
int
i
=
0
,
j
=
0
;
i
<
_recognizerOffsets
.
length
;
i
+=
2
,
j
++)
{
final
int
start
=
_recognizerOffsets
[
i
];
final
int
end
=
_recognizerOffsets
[
i
+
1
];
if
(
current
!=
start
)
{
final
SemanticsNode
node
=
SemanticsNode
();
final
SemanticsConfiguration
configuration
=
buildSemanticsConfig
(
current
,
start
);
...
...
@@ -804,38 +558,19 @@ class RenderParagraph extends RenderBox
node
.
rect
=
currentRect
;
newChildren
.
add
(
node
);
}
final
dynamic
inlineElement
=
_inlineSemanticsElements
[
j
];
final
SemanticsConfiguration
configuration
=
buildSemanticsConfig
(
start
,
end
,
includeText:
false
);
if
(
inlineElement
!=
null
)
{
// Add semantics for this recognizer.
final
SemanticsNode
node
=
SemanticsNode
();
if
(
inlineElement
is
TapGestureRecognizer
)
{
final
TapGestureRecognizer
recognizer
=
inlineElement
;
configuration
.
onTap
=
recognizer
.
onTap
;
}
else
if
(
inlineElement
is
LongPressGestureRecognizer
)
{
final
LongPressGestureRecognizer
recognizer
=
inlineElement
;
configuration
.
onLongPress
=
recognizer
.
onLongPress
;
}
else
{
assert
(
false
);
}
node
.
updateWith
(
config:
configuration
);
node
.
rect
=
currentRect
;
newChildren
.
add
(
node
);
}
else
if
(
childIndex
<
children
.
length
)
{
// Add semantics for this placeholder. Semantics are precomputed in the children
// argument.
final
SemanticsNode
childNode
=
children
.
elementAt
(
childIndex
);
final
TextParentData
parentData
=
child
.
parentData
;
childNode
.
rect
=
Rect
.
fromLTWH
(
childNode
.
rect
.
left
,
childNode
.
rect
.
top
,
childNode
.
rect
.
width
*
parentData
.
scale
,
childNode
.
rect
.
height
*
parentData
.
scale
,
);
newChildren
.
add
(
children
.
elementAt
(
childIndex
));
childIndex
+=
1
;
child
=
childAfter
(
child
);
final
SemanticsNode
node
=
SemanticsNode
();
final
SemanticsConfiguration
configuration
=
buildSemanticsConfig
(
start
,
end
);
final
GestureRecognizer
recognizer
=
_recognizers
[
j
];
if
(
recognizer
is
TapGestureRecognizer
)
{
configuration
.
onTap
=
recognizer
.
onTap
;
}
else
if
(
recognizer
is
LongPressGestureRecognizer
)
{
configuration
.
onLongPress
=
recognizer
.
onLongPress
;
}
else
{
assert
(
false
);
}
node
.
updateWith
(
config:
configuration
);
node
.
rect
=
currentRect
;
newChildren
.
add
(
node
);
current
=
end
;
}
if
(
current
<
rawLabel
.
length
)
{
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/basic.dart
View file @
4e5cf5ef
...
...
@@ -12,7 +12,6 @@ import 'package:flutter/services.dart';
import
'debug.dart'
;
import
'framework.dart'
;
import
'localizations.dart'
;
import
'widget_span.dart'
;
export
'package:flutter/animation.dart'
;
export
'package:flutter/foundation.dart'
show
...
...
@@ -4914,9 +4913,7 @@ class Flow extends MultiChildRenderObjectWidget {
/// * [TextSpan], which is used to describe the text in a paragraph.
/// * [Text], which automatically applies the ambient styles described by a
/// [DefaultTextStyle] to a single string.
/// * [Text.rich], a const text widget that provides similar functionality
/// as [RichText]. [Text.rich] will inherit [TextStyle] from [DefaultTextStyle].
class
RichText
extends
MultiChildRenderObjectWidget
{
class
RichText
extends
LeafRenderObjectWidget
{
/// Creates a paragraph of rich text.
///
/// The [text], [textAlign], [softWrap], [overflow], and [textScaleFactor]
...
...
@@ -4927,7 +4924,7 @@ class RichText extends MultiChildRenderObjectWidget {
///
/// The [textDirection], if null, defaults to the ambient [Directionality],
/// which in that case must not be null.
RichText
({
const
RichText
({
Key
key
,
@required
this
.
text
,
this
.
textAlign
=
TextAlign
.
start
,
...
...
@@ -4946,23 +4943,10 @@ class RichText extends MultiChildRenderObjectWidget {
assert
(
textScaleFactor
!=
null
),
assert
(
maxLines
==
null
||
maxLines
>
0
),
assert
(
textWidthBasis
!=
null
),
super
(
key:
key
,
children:
_extractChildren
(
text
));
// Traverses the InlineSpan tree and depth-first collects the list of
// child widgets that are created in WidgetSpans.
static
List
<
Widget
>
_extractChildren
(
InlineSpan
span
)
{
final
List
<
Widget
>
result
=
<
Widget
>[];
span
.
visitChildren
((
InlineSpan
span
)
{
if
(
span
is
WidgetSpan
)
{
result
.
add
(
span
.
child
);
}
return
true
;
});
return
result
;
}
super
(
key:
key
);
/// The text to display in this widget.
final
Inline
Span
text
;
final
Text
Span
text
;
/// How the text should be aligned horizontally.
final
TextAlign
textAlign
;
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/text.dart
View file @
4e5cf5ef
...
...
@@ -256,16 +256,9 @@ class Text extends StatelessWidget {
textSpan
=
null
,
super
(
key:
key
);
/// Creates a text widget with a [InlineSpan].
///
/// The following subclasses of [InlineSpan] may be used to build rich text:
///
/// * [TextSpan]s define text and children [InlineSpan]s.
/// * [WidgetSpan]s define embedded inline widgets.
/// Creates a text widget with a [TextSpan].
///
/// The [textSpan] parameter must not be null.
///
/// See [RichText] which provides a lower-level way to draw text.
const
Text
.
rich
(
this
.
textSpan
,
{
Key
key
,
...
...
@@ -292,10 +285,10 @@ class Text extends StatelessWidget {
/// This will be null if a [textSpan] is provided instead.
final
String
data
;
/// The text to display as a [
Inline
Span].
/// The text to display as a [
Text
Span].
///
/// This will be null if [data] is provided instead.
final
Inline
Span
textSpan
;
final
Text
Span
textSpan
;
/// If non-null, the style to use for this text.
///
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/widget_inspector.dart
View file @
4e5cf5ef
...
...
@@ -2752,8 +2752,7 @@ class _InspectorOverlayLayer extends Layer {
)
{
canvas
.
save
();
final
double
maxWidth
=
size
.
width
-
2
*
(
_kScreenEdgeMargin
+
_kTooltipPadding
);
final
TextSpan
textSpan
=
_textPainter
?.
text
;
if
(
_textPainter
==
null
||
textSpan
.
text
!=
message
||
_textPainterMaxWidth
!=
maxWidth
)
{
if
(
_textPainter
==
null
||
_textPainter
.
text
.
text
!=
message
||
_textPainterMaxWidth
!=
maxWidth
)
{
_textPainterMaxWidth
=
maxWidth
;
_textPainter
=
TextPainter
()
..
maxLines
=
_kMaxTooltipLines
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/widgets/widget_span.dart
deleted
100644 → 0
View file @
3dd87ff7
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:ui'
as
ui
show
ParagraphBuilder
,
PlaceholderAlignment
;
import
'package:flutter/painting.dart'
;
import
'framework.dart'
;
/// An immutable widget that is embedded inline within text.
///
/// The [child] property is the widget that will be embedded. Children are
/// constrained by the width of the paragraph.
///
/// The [child] property may contain its own [Widget] children (if applicable),
/// including [Text] and [RichText] widgets which may include additional
/// [WidgetSpan]s. Child [Text] and [RichText] widgets will be laid out
/// independently and occupy a rectangular space in the parent text layout.
///
/// [WidgetSpan]s will be ignored when passed into a [TextPainter] directly.
/// To properly layout and paint the [child] widget, [WidgetSpan] should be
/// passed into a [Text.rich] widget.
///
/// {@tool sample}
///
/// A card with `Hello World!` embedded inline within a TextSpan tree.
///
/// ```dart
/// Text.rich(
/// TextSpan(
/// children: <InlineSpan>[
/// TextSpan(text: 'Flutter is'),
/// WidgetSpan(
/// child: SizedBox(
/// width: 120,
/// height: 50,
/// child: Card(
/// child: Center(
/// child: Text('Hello World!')
/// )
/// ),
/// )
/// ),
/// TextSpan(text: 'the best!'),
/// ],
/// )
/// )
/// ```
/// {@end-tool}
///
/// [WidgetSpan] contributes the semantics of the [WidgetSpan.child] to the
/// semantics tree.
///
/// See also:
///
/// * [TextSpan], a node that represents text in an [InlineSpan] tree.
/// * [Text], a widget for showing uniformly-styled text.
/// * [RichText], a widget for finer control of text rendering.
/// * [TextPainter], a class for painting [InlineSpan] objects on a [Canvas].
@immutable
class
WidgetSpan
extends
PlaceholderSpan
{
/// Creates a [WidgetSpan] with the given values.
///
/// The [child] property must be non-null. [WidgetSpan] is a leaf node in
/// the [InlineSpan] tree. Child widgets are constrained by the width of the
/// paragraph they occupy. Child widget heights are unconstrained, and may
/// cause the text to overflow and be ellipsized/truncated.
///
/// A [TextStyle] may be provided with the [style] property, but only the
/// decoration, foreground, background, and spacing options will be used.
const
WidgetSpan
({
@required
this
.
child
,
ui
.
PlaceholderAlignment
alignment
=
ui
.
PlaceholderAlignment
.
bottom
,
TextBaseline
baseline
,
TextStyle
style
,
})
:
assert
(
child
!=
null
),
assert
((
identical
(
alignment
,
ui
.
PlaceholderAlignment
.
aboveBaseline
)
||
identical
(
alignment
,
ui
.
PlaceholderAlignment
.
belowBaseline
)
||
identical
(
alignment
,
ui
.
PlaceholderAlignment
.
baseline
))
?
baseline
!=
null
:
true
),
super
(
alignment:
alignment
,
baseline:
baseline
,
style:
style
,
);
/// The widget to embed inline within text.
final
Widget
child
;
/// Adds a placeholder box to the paragraph builder if a size has been
/// calculated for the widget.
///
/// Sizes are provided through `dimensions`, which should contain a 1:1
/// in-order mapping of widget to laid-out dimensions. If no such dimension
/// is provided, the widget will be skipped.
///
/// The `textScaleFactor` will be applied to the laid-out size of the widget.
@override
void
build
(
ui
.
ParagraphBuilder
builder
,
{
double
textScaleFactor
=
1.0
,
@required
List
<
PlaceholderDimensions
>
dimensions
})
{
assert
(
debugAssertIsValid
());
assert
(
dimensions
!=
null
);
final
bool
hasStyle
=
style
!=
null
;
if
(
hasStyle
)
{
builder
.
pushStyle
(
style
.
getTextStyle
(
textScaleFactor:
textScaleFactor
));
}
assert
(
builder
.
placeholderCount
<
dimensions
.
length
);
final
PlaceholderDimensions
currentDimensions
=
dimensions
[
builder
.
placeholderCount
];
builder
.
addPlaceholder
(
currentDimensions
.
size
.
width
,
currentDimensions
.
size
.
height
,
alignment
,
scale:
textScaleFactor
,
baseline:
currentDimensions
.
baseline
,
baselineOffset:
currentDimensions
.
baselineOffset
,
);
if
(
hasStyle
)
{
builder
.
pop
();
}
}
/// Calls `visitor` on this [WidgetSpan]. There are no children spans to walk.
@override
bool
visitChildren
(
InlineSpanVisitor
visitor
)
{
return
visitor
(
this
);
}
@override
InlineSpan
getSpanForPositionVisitor
(
TextPosition
position
,
Accumulator
offset
)
{
return
null
;
}
@override
int
codeUnitAtVisitor
(
int
index
,
Accumulator
offset
)
{
return
null
;
}
@override
RenderComparison
compareTo
(
InlineSpan
other
)
{
if
(
identical
(
this
,
other
))
return
RenderComparison
.
identical
;
if
(
other
.
runtimeType
!=
runtimeType
)
return
RenderComparison
.
layout
;
if
((
style
==
null
)
!=
(
other
.
style
==
null
))
return
RenderComparison
.
layout
;
final
WidgetSpan
typedOther
=
other
;
if
(
child
!=
typedOther
.
child
||
alignment
!=
typedOther
.
alignment
)
{
return
RenderComparison
.
layout
;
}
RenderComparison
result
=
RenderComparison
.
identical
;
if
(
style
!=
null
)
{
final
RenderComparison
candidate
=
style
.
compareTo
(
other
.
style
);
if
(
candidate
.
index
>
result
.
index
)
result
=
candidate
;
if
(
result
==
RenderComparison
.
layout
)
return
result
;
}
return
result
;
}
@override
bool
operator
==(
dynamic
other
)
{
if
(
identical
(
this
,
other
))
return
true
;
if
(
other
.
runtimeType
!=
runtimeType
)
return
false
;
if
(
super
!=
other
)
return
false
;
final
WidgetSpan
typedOther
=
other
;
return
typedOther
.
child
==
child
&&
typedOther
.
alignment
==
alignment
&&
typedOther
.
baseline
==
baseline
;
}
@override
int
get
hashCode
=>
hashValues
(
super
.
hashCode
,
child
,
alignment
,
baseline
);
/// Returns the text span that contains the given position in the text.
@override
InlineSpan
getSpanForPosition
(
TextPosition
position
)
{
assert
(
debugAssertIsValid
());
return
null
;
}
/// In debug mode, throws an exception if the object is not in a
/// valid configuration. Otherwise, returns true.
///
/// This is intended to be used as follows:
///
/// ```dart
/// assert(myWidgetSpan.debugAssertIsValid());
/// ```
@override
bool
debugAssertIsValid
()
{
// WidgetSpans are always valid as asserts prevent invalid WidgetSpans
// from being constructed.
return
true
;
}
}
This diff is collapsed.
Click to expand it.
packages/flutter/lib/widgets.dart
View file @
4e5cf5ef
...
...
@@ -108,5 +108,4 @@ export 'src/widgets/value_listenable_builder.dart';
export
'src/widgets/viewport.dart'
;
export
'src/widgets/visibility.dart'
;
export
'src/widgets/widget_inspector.dart'
;
export
'src/widgets/widget_span.dart'
;
export
'src/widgets/will_pop_scope.dart'
;
This diff is collapsed.
Click to expand it.
packages/flutter/test/painting/text_painter_rtl_test.dart
View file @
4e5cf5ef
...
...
@@ -43,8 +43,7 @@ void main() {
// 0 12345678 9 101234567 18 90123456 27
style:
TextStyle
(
fontFamily:
'Ahem'
,
fontSize:
10.0
),
);
TextSpan
textSpan
=
painter
.
text
;
expect
(
textSpan
.
text
.
length
,
28
);
expect
(
painter
.
text
.
text
.
length
,
28
);
painter
.
layout
();
// The skips here are because the old rendering code considers the bidi formatting characters
...
...
@@ -128,8 +127,7 @@ void main() {
);
final
List
<
List
<
TextBox
>>
list
=
<
List
<
TextBox
>>[];
textSpan
=
painter
.
text
;
for
(
int
index
=
0
;
index
<
textSpan
.
text
.
length
;
index
+=
1
)
for
(
int
index
=
0
;
index
<
painter
.
text
.
text
.
length
;
index
+=
1
)
list
.
add
(
painter
.
getBoxesForSelection
(
TextSelection
(
baseOffset:
index
,
extentOffset:
index
+
1
)));
expect
(
list
,
const
<
List
<
TextBox
>>[
<
TextBox
>[],
// U+202E, non-printing Unicode bidi formatting character
...
...
@@ -174,8 +172,7 @@ void main() {
// 0 12345678 9 101234567 18 90123456 27
style:
TextStyle
(
fontFamily:
'Ahem'
,
fontSize:
10.0
),
);
final
TextSpan
textSpan
=
painter
.
text
;
expect
(
textSpan
.
text
.
length
,
28
);
expect
(
painter
.
text
.
text
.
length
,
28
);
painter
.
layout
();
final
TextRange
hebrew1
=
painter
.
getWordBoundary
(
const
TextPosition
(
offset:
4
,
affinity:
TextAffinity
.
downstream
));
...
...
@@ -264,8 +261,7 @@ void main() {
text:
'A
\
u05D0'
,
// A, Alef
style:
TextStyle
(
fontFamily:
'Ahem'
,
fontSize:
10.0
),
);
final
TextSpan
textSpan
=
painter
.
text
;
expect
(
textSpan
.
text
.
length
,
2
);
expect
(
painter
.
text
.
text
.
length
,
2
);
painter
.
layout
(
maxWidth:
10.0
);
for
(
int
index
=
0
;
index
<=
2
;
index
+=
1
)
{
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/painting/text_painter_test.dart
View file @
4e5cf5ef
...
...
@@ -5,7 +5,6 @@
import
'dart:ui'
as
ui
;
import
'package:flutter/painting.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
...
...
@@ -635,98 +634,4 @@ void main() {
expect
(
caretOffset
.
dx
,
closeTo
(
0.0
,
0.0001
));
expect
(
caretOffset
.
dy
,
closeTo
(
0.0
,
0.0001
));
});
test
(
'TextPainter widget span'
,
()
{
final
TextPainter
painter
=
TextPainter
()
..
textDirection
=
TextDirection
.
ltr
;
const
String
text
=
'test'
;
painter
.
text
=
const
TextSpan
(
text:
text
,
children:
<
InlineSpan
>[
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
TextSpan
(
text:
text
),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
TextSpan
(
text:
text
),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
WidgetSpan
(
child:
SizedBox
(
width:
50
,
height:
30
)),
]
);
// We provide dimensions for the widgets
painter
.
setPlaceholderDimensions
(
const
<
PlaceholderDimensions
>[
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
51
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
PlaceholderDimensions
(
size:
Size
(
50
,
30
),
baselineOffset:
25
,
alignment:
ui
.
PlaceholderAlignment
.
bottom
),
]);
painter
.
layout
(
maxWidth:
500
);
// Now, each of the WidgetSpans will have their own placeholder 'hole'.
Offset
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
1
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
14
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
4
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
56
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
5
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
106
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
6
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
120
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
10
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
212
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
11
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
262
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
12
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
276
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
13
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
290
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
14
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
304
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
15
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
318
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
16
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
368
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
17
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
418
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
18
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
0
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
19
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
50
);
caretOffset
=
painter
.
getOffsetForCaret
(
const
ui
.
TextPosition
(
offset:
23
),
ui
.
Rect
.
zero
);
expect
(
caretOffset
.
dx
,
250
);
expect
(
painter
.
inlinePlaceholderBoxes
.
length
,
14
);
expect
(
painter
.
inlinePlaceholderBoxes
[
0
],
const
TextBox
.
fromLTRBD
(
56
,
0
,
106
,
30
,
TextDirection
.
ltr
));
expect
(
painter
.
inlinePlaceholderBoxes
[
2
],
const
TextBox
.
fromLTRBD
(
212
,
0
,
262
,
30
,
TextDirection
.
ltr
));
expect
(
painter
.
inlinePlaceholderBoxes
[
3
],
const
TextBox
.
fromLTRBD
(
318
,
0
,
368
,
30
,
TextDirection
.
ltr
));
expect
(
painter
.
inlinePlaceholderBoxes
[
4
],
const
TextBox
.
fromLTRBD
(
368
,
0
,
418
,
30
,
TextDirection
.
ltr
));
expect
(
painter
.
inlinePlaceholderBoxes
[
5
],
const
TextBox
.
fromLTRBD
(
418
,
0
,
468
,
30
,
TextDirection
.
ltr
));
// line should break here
expect
(
painter
.
inlinePlaceholderBoxes
[
6
],
const
TextBox
.
fromLTRBD
(
0
,
30
,
50
,
60
,
TextDirection
.
ltr
));
expect
(
painter
.
inlinePlaceholderBoxes
[
7
],
const
TextBox
.
fromLTRBD
(
50
,
30
,
100
,
60
,
TextDirection
.
ltr
));
expect
(
painter
.
inlinePlaceholderBoxes
[
10
],
const
TextBox
.
fromLTRBD
(
200
,
30
,
250
,
60
,
TextDirection
.
ltr
));
expect
(
painter
.
inlinePlaceholderBoxes
[
11
],
const
TextBox
.
fromLTRBD
(
250
,
30
,
300
,
60
,
TextDirection
.
ltr
));
expect
(
painter
.
inlinePlaceholderBoxes
[
12
],
const
TextBox
.
fromLTRBD
(
300
,
30
,
351
,
60
,
TextDirection
.
ltr
));
expect
(
painter
.
inlinePlaceholderBoxes
[
13
],
const
TextBox
.
fromLTRBD
(
351
,
30
,
401
,
60
,
TextDirection
.
ltr
));
});
}
This diff is collapsed.
Click to expand it.
packages/flutter/test/painting/text_span_test.dart
View file @
4e5cf5ef
...
...
@@ -3,17 +3,17 @@
// found in the LICENSE file.
import
'package:flutter/painting.dart'
;
import
'package:flutter
/widgets.dart'
;
import
'package:flutter
_test/flutter_test.dart'
show
nonconst
;
import
'../flutter_test_alternative.dart'
;
void
main
(
)
{
test
(
'TextSpan equals'
,
()
{
const
TextSpan
a1
=
TextSpan
(
text:
'a'
);
const
TextSpan
a2
=
TextSpan
(
text:
'a'
);
const
TextSpan
b1
=
TextSpan
(
children:
<
TextSpan
>[
a1
]);
const
TextSpan
b2
=
TextSpan
(
children:
<
TextSpan
>[
a2
]);
const
TextSpan
c1
=
TextSpan
(
text:
null
);
const
TextSpan
c2
=
TextSpan
(
text:
null
);
final
TextSpan
a1
=
TextSpan
(
text:
nonconst
(
'a'
)
);
final
TextSpan
a2
=
TextSpan
(
text:
nonconst
(
'a'
)
);
final
TextSpan
b1
=
TextSpan
(
children:
<
TextSpan
>[
a1
]);
final
TextSpan
b2
=
TextSpan
(
children:
<
TextSpan
>[
a2
]);
final
TextSpan
c1
=
TextSpan
(
text:
nonconst
(
null
)
);
final
TextSpan
c2
=
TextSpan
(
text:
nonconst
(
null
)
);
expect
(
a1
==
a2
,
isTrue
);
expect
(
b1
==
b2
,
isTrue
);
...
...
@@ -73,18 +73,6 @@ void main() {
expect
(
textSpan
.
toPlainText
(),
'abc'
);
});
test
(
'WidgetSpan toPlainText'
,
()
{
const
TextSpan
textSpan
=
TextSpan
(
text:
'a'
,
children:
<
InlineSpan
>[
TextSpan
(
text:
'b'
),
WidgetSpan
(
child:
SizedBox
(
width:
10
,
height:
10
)),
TextSpan
(
text:
'c'
),
],
);
expect
(
textSpan
.
toPlainText
(),
'ab
\
uFFFCc'
);
});
test
(
'TextSpan toPlainText with semanticsLabel'
,
()
{
const
TextSpan
textSpan
=
TextSpan
(
text:
'a'
,
...
...
@@ -96,117 +84,4 @@ void main() {
expect
(
textSpan
.
toPlainText
(),
'afooc'
);
expect
(
textSpan
.
toPlainText
(
includeSemanticsLabels:
false
),
'abc'
);
});
test
(
'TextSpan widget change test'
,
()
{
const
TextSpan
textSpan1
=
TextSpan
(
text:
'a'
,
children:
<
InlineSpan
>[
TextSpan
(
text:
'b'
),
WidgetSpan
(
child:
SizedBox
(
width:
10
,
height:
10
)),
TextSpan
(
text:
'c'
),
],
);
const
TextSpan
textSpan2
=
TextSpan
(
text:
'a'
,
children:
<
InlineSpan
>[
TextSpan
(
text:
'b'
),
WidgetSpan
(
child:
SizedBox
(
width:
10
,
height:
10
)),
TextSpan
(
text:
'c'
),
],
);
const
TextSpan
textSpan3
=
TextSpan
(
text:
'a'
,
children:
<
InlineSpan
>[
TextSpan
(
text:
'b'
),
WidgetSpan
(
child:
SizedBox
(
width:
11
,
height:
10
)),
TextSpan
(
text:
'c'
),
],
);
const
TextSpan
textSpan4
=
TextSpan
(
text:
'a'
,
children:
<
InlineSpan
>[
TextSpan
(
text:
'b'
),
WidgetSpan
(
child:
Text
(
'test'
)),
TextSpan
(
text:
'c'
),
],
);
const
TextSpan
textSpan5
=
TextSpan
(
text:
'a'
,
children:
<
InlineSpan
>[
TextSpan
(
text:
'b'
),
WidgetSpan
(
child:
Text
(
'different!'
)),
TextSpan
(
text:
'c'
),
],
);
const
TextSpan
textSpan6
=
TextSpan
(
text:
'a'
,
children:
<
InlineSpan
>[
TextSpan
(
text:
'b'
),
WidgetSpan
(
child:
SizedBox
(
width:
10
,
height:
10
),
alignment:
PlaceholderAlignment
.
top
,
),
TextSpan
(
text:
'c'
),
],
);
expect
(
textSpan1
.
compareTo
(
textSpan3
),
RenderComparison
.
layout
);
expect
(
textSpan1
.
compareTo
(
textSpan4
),
RenderComparison
.
layout
);
expect
(
textSpan1
.
compareTo
(
textSpan1
),
RenderComparison
.
identical
);
expect
(
textSpan2
.
compareTo
(
textSpan2
),
RenderComparison
.
identical
);
expect
(
textSpan3
.
compareTo
(
textSpan3
),
RenderComparison
.
identical
);
expect
(
textSpan2
.
compareTo
(
textSpan3
),
RenderComparison
.
layout
);
expect
(
textSpan4
.
compareTo
(
textSpan5
),
RenderComparison
.
layout
);
expect
(
textSpan3
.
compareTo
(
textSpan5
),
RenderComparison
.
layout
);
expect
(
textSpan2
.
compareTo
(
textSpan5
),
RenderComparison
.
layout
);
expect
(
textSpan1
.
compareTo
(
textSpan5
),
RenderComparison
.
layout
);
expect
(
textSpan1
.
compareTo
(
textSpan6
),
RenderComparison
.
layout
);
});
test
(
'TextSpan nested widget change test'
,
()
{
const
TextSpan
textSpan1
=
TextSpan
(
text:
'a'
,
children:
<
InlineSpan
>[
TextSpan
(
text:
'b'
),
WidgetSpan
(
child:
Text
.
rich
(
TextSpan
(
children:
<
InlineSpan
>[
WidgetSpan
(
child:
SizedBox
(
width:
10
,
height:
10
)),
TextSpan
(
text:
'The sky is falling :)'
)
],
)
),
),
TextSpan
(
text:
'c'
),
],
);
const
TextSpan
textSpan2
=
TextSpan
(
text:
'a'
,
children:
<
InlineSpan
>[
TextSpan
(
text:
'b'
),
WidgetSpan
(
child:
Text
.
rich
(
TextSpan
(
children:
<
InlineSpan
>[
WidgetSpan
(
child:
SizedBox
(
width:
10
,
height:
11
)),
TextSpan
(
text:
'The sky is falling :)'
)
],
)
),
),
TextSpan
(
text:
'c'
),
],
);
expect
(
textSpan1
.
compareTo
(
textSpan2
),
RenderComparison
.
layout
);
expect
(
textSpan1
.
compareTo
(
textSpan1
),
RenderComparison
.
identical
);
expect
(
textSpan2
.
compareTo
(
textSpan2
),
RenderComparison
.
identical
);
});
}
This diff is collapsed.
Click to expand it.
packages/flutter/test/rendering/paragraph_test.dart
View file @
4e5cf5ef
...
...
@@ -5,7 +5,6 @@
import
'dart:ui'
as
ui
show
TextBox
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
...
...
@@ -325,93 +324,4 @@ void main() {
expect
(
paragraph
.
locale
,
const
Locale
(
'ja'
,
'JP'
));
});
test
(
'inline widgets test'
,
()
{
const
TextSpan
text
=
TextSpan
(
text:
'a'
,
style:
TextStyle
(
fontSize:
10.0
),
children:
<
InlineSpan
>[
WidgetSpan
(
child:
SizedBox
(
width:
21
,
height:
21
)),
WidgetSpan
(
child:
SizedBox
(
width:
21
,
height:
21
)),
TextSpan
(
text:
'a'
),
WidgetSpan
(
child:
SizedBox
(
width:
21
,
height:
21
)),
],
);
// Fake the render boxes that correspond to the WidgetSpans. We use
// RenderParagraph to reduce dependencies this test has.
final
List
<
RenderBox
>
renderBoxes
=
<
RenderBox
>[];
renderBoxes
.
add
(
RenderParagraph
(
const
TextSpan
(
text:
'b'
),
textDirection:
TextDirection
.
ltr
));
renderBoxes
.
add
(
RenderParagraph
(
const
TextSpan
(
text:
'b'
),
textDirection:
TextDirection
.
ltr
));
renderBoxes
.
add
(
RenderParagraph
(
const
TextSpan
(
text:
'b'
),
textDirection:
TextDirection
.
ltr
));
final
RenderParagraph
paragraph
=
RenderParagraph
(
text
,
textDirection:
TextDirection
.
ltr
,
children:
renderBoxes
,
);
layout
(
paragraph
,
constraints:
const
BoxConstraints
(
maxWidth:
100.0
));
final
List
<
ui
.
TextBox
>
boxes
=
paragraph
.
getBoxesForSelection
(
const
TextSelection
(
baseOffset:
0
,
extentOffset:
8
)
);
expect
(
boxes
.
length
,
equals
(
5
));
expect
(
boxes
[
0
],
const
TextBox
.
fromLTRBD
(
0.0
,
4.0
,
10.0
,
14.0
,
TextDirection
.
ltr
));
expect
(
boxes
[
1
],
const
TextBox
.
fromLTRBD
(
10.0
,
0.0
,
24.0
,
14.0
,
TextDirection
.
ltr
));
expect
(
boxes
[
2
],
const
TextBox
.
fromLTRBD
(
24.0
,
0.0
,
38.0
,
14.0
,
TextDirection
.
ltr
));
expect
(
boxes
[
3
],
const
TextBox
.
fromLTRBD
(
38.0
,
4.0
,
48.0
,
14.0
,
TextDirection
.
ltr
));
expect
(
boxes
[
4
],
const
TextBox
.
fromLTRBD
(
48.0
,
0.0
,
62.0
,
14.0
,
TextDirection
.
ltr
));
// Ahem-based tests don't yet quite work on Windows or some MacOS environments
},
skip:
isWindows
||
isMacOS
);
test
(
'inline widgets multiline test'
,
()
{
const
TextSpan
text
=
TextSpan
(
text:
'a'
,
style:
TextStyle
(
fontSize:
10.0
),
children:
<
InlineSpan
>[
WidgetSpan
(
child:
SizedBox
(
width:
21
,
height:
21
)),
WidgetSpan
(
child:
SizedBox
(
width:
21
,
height:
21
)),
TextSpan
(
text:
'a'
),
WidgetSpan
(
child:
SizedBox
(
width:
21
,
height:
21
)),
WidgetSpan
(
child:
SizedBox
(
width:
21
,
height:
21
)),
WidgetSpan
(
child:
SizedBox
(
width:
21
,
height:
21
)),
WidgetSpan
(
child:
SizedBox
(
width:
21
,
height:
21
)),
WidgetSpan
(
child:
SizedBox
(
width:
21
,
height:
21
)),
],
);
// Fake the render boxes that correspond to the WidgetSpans. We use
// RenderParagraph to reduce dependencies this test has.
final
List
<
RenderBox
>
renderBoxes
=
<
RenderBox
>[];
renderBoxes
.
add
(
RenderParagraph
(
const
TextSpan
(
text:
'b'
),
textDirection:
TextDirection
.
ltr
));
renderBoxes
.
add
(
RenderParagraph
(
const
TextSpan
(
text:
'b'
),
textDirection:
TextDirection
.
ltr
));
renderBoxes
.
add
(
RenderParagraph
(
const
TextSpan
(
text:
'b'
),
textDirection:
TextDirection
.
ltr
));
renderBoxes
.
add
(
RenderParagraph
(
const
TextSpan
(
text:
'b'
),
textDirection:
TextDirection
.
ltr
));
renderBoxes
.
add
(
RenderParagraph
(
const
TextSpan
(
text:
'b'
),
textDirection:
TextDirection
.
ltr
));
renderBoxes
.
add
(
RenderParagraph
(
const
TextSpan
(
text:
'b'
),
textDirection:
TextDirection
.
ltr
));
renderBoxes
.
add
(
RenderParagraph
(
const
TextSpan
(
text:
'b'
),
textDirection:
TextDirection
.
ltr
));
final
RenderParagraph
paragraph
=
RenderParagraph
(
text
,
textDirection:
TextDirection
.
ltr
,
children:
renderBoxes
,
);
layout
(
paragraph
,
constraints:
const
BoxConstraints
(
maxWidth:
50.0
));
final
List
<
ui
.
TextBox
>
boxes
=
paragraph
.
getBoxesForSelection
(
const
TextSelection
(
baseOffset:
0
,
extentOffset:
12
)
);
expect
(
boxes
.
length
,
equals
(
9
));
expect
(
boxes
[
0
],
const
TextBox
.
fromLTRBD
(
0.0
,
4.0
,
10.0
,
14.0
,
TextDirection
.
ltr
));
expect
(
boxes
[
1
],
const
TextBox
.
fromLTRBD
(
10.0
,
0.0
,
24.0
,
14.0
,
TextDirection
.
ltr
));
expect
(
boxes
[
2
],
const
TextBox
.
fromLTRBD
(
24.0
,
0.0
,
38.0
,
14.0
,
TextDirection
.
ltr
));
expect
(
boxes
[
3
],
const
TextBox
.
fromLTRBD
(
38.0
,
4.0
,
48.0
,
14.0
,
TextDirection
.
ltr
));
// Wraps
expect
(
boxes
[
4
],
const
TextBox
.
fromLTRBD
(
0.0
,
14.0
,
14.0
,
28.0
,
TextDirection
.
ltr
));
expect
(
boxes
[
5
],
const
TextBox
.
fromLTRBD
(
14.0
,
14.0
,
28.0
,
28.0
,
TextDirection
.
ltr
));
expect
(
boxes
[
6
],
const
TextBox
.
fromLTRBD
(
28.0
,
14.0
,
42.0
,
28.0
,
TextDirection
.
ltr
));
// Wraps
expect
(
boxes
[
7
],
const
TextBox
.
fromLTRBD
(
0.0
,
28.0
,
14.0
,
42.0
,
TextDirection
.
ltr
));
expect
(
boxes
[
8
],
const
TextBox
.
fromLTRBD
(
14.0
,
28.0
,
28.0
,
42.0
,
TextDirection
.
ltr
));
// Ahem-based tests don't yet quite work on Windows or some MacOS environments
},
skip:
isWindows
||
isMacOS
);
}
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/backdrop_filter_test.dart
View file @
4e5cf5ef
...
...
@@ -10,7 +10,6 @@ import 'package:flutter/material.dart';
void
main
(
)
{
testWidgets
(
'BackdropFilter
\'
s cull rect does not shrink'
,
(
WidgetTester
tester
)
async
{
tester
.
binding
.
addTime
(
const
Duration
(
seconds:
15
));
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Scaffold
(
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/basic_test.dart
View file @
4e5cf5ef
...
...
@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
import
'package:flutter/widgets.dart'
;
import
'package:flutter/rendering.dart'
;
void
main
(
)
{
group
(
'PhysicalShape'
,
()
{
testWidgets
(
'properties'
,
(
WidgetTester
tester
)
async
{
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/editable_text_test.dart
View file @
4e5cf5ef
...
...
@@ -1870,9 +1870,8 @@ void main() {
final
RenderEditable
renderEditable
=
findRenderEditable
(
tester
);
// The actual text span is split into 3 parts with the middle part underlined.
expect
(
renderEditable
.
text
.
children
.
length
,
3
);
final
TextSpan
textSpan
=
renderEditable
.
text
.
children
[
1
];
expect
(
textSpan
.
text
,
'composing'
);
expect
(
textSpan
.
style
.
decoration
,
TextDecoration
.
underline
);
expect
(
renderEditable
.
text
.
children
[
1
].
text
,
'composing'
);
expect
(
renderEditable
.
text
.
children
[
1
].
style
.
decoration
,
TextDecoration
.
underline
);
focusNode
.
unfocus
();
await
tester
.
pump
();
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/text_golden_test.dart
View file @
4e5cf5ef
...
...
@@ -151,15 +151,16 @@ void main() {
decoration:
const
BoxDecoration
(
color:
Colors
.
green
,
),
child:
Text
.
rich
(
TextSpan
(
child:
RichText
(
textDirection:
TextDirection
.
ltr
,
text:
TextSpan
(
text:
'text1 '
,
style:
TextStyle
(
color:
translucentGreen
,
background:
Paint
()
..
color
=
red
.
withOpacity
(
0.5
),
),
children:
<
Inline
Span
>[
children:
<
Text
Span
>[
TextSpan
(
text:
'text2'
,
style:
TextStyle
(
...
...
@@ -170,7 +171,6 @@ void main() {
),
],
),
textDirection:
TextDirection
.
ltr
,
),
),
),
...
...
@@ -242,7 +242,7 @@ void main() {
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.StrutDefault.png'
),
);
},
skip:
true
);
// Should only be on linux (skip: !isLinux).
},
skip:
true
);
// Should only be on linux (skip: !
Platform.
isLinux).
// Disabled for now until font inconsistency is resolved.
testWidgets
(
'Strut text 1'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -270,7 +270,7 @@ void main() {
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.Strut.1.1.png'
),
);
},
skip:
true
);
// Should only be on linux (skip: !isLinux).
},
skip:
true
);
// Should only be on linux (skip: !
Platform.
isLinux).
// Disabled for now until font inconsistency is resolved.
testWidgets
(
'Strut text 2'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -299,7 +299,7 @@ void main() {
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.Strut.2.1.png'
),
);
},
skip:
true
);
// Should only be on linux (skip: !isLinux).
},
skip:
true
);
// Should only be on linux (skip: !
Platform.
isLinux).
// Disabled for now until font inconsistency is resolved.
testWidgets
(
'Strut text rich'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -319,7 +319,7 @@ void main() {
color:
Colors
.
red
,
fontSize:
30
,
),
children:
<
Inline
Span
>[
children:
<
Text
Span
>[
TextSpan
(
text:
'Second line!
\n
'
,
style:
TextStyle
(
...
...
@@ -351,7 +351,7 @@ void main() {
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.Strut.3.1.png'
),
);
},
skip:
true
);
// Should only be on linux (skip: !isLinux).
},
skip:
true
);
// Should only be on linux (skip: !
Platform.
isLinux).
// Disabled for now until font inconsistency is resolved.
testWidgets
(
'Strut text font fallback'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -387,7 +387,7 @@ void main() {
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.Strut.4.1.png'
),
);
},
skip:
true
);
// Should only be on linux (skip: !isLinux).
},
skip:
true
);
// Should only be on linux (skip: !
Platform.
isLinux).
// Disabled for now until font inconsistency is resolved.
testWidgets
(
'Strut text rich forceStrutHeight'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -407,7 +407,7 @@ void main() {
color:
Colors
.
red
,
fontSize:
30
,
),
children:
<
Inline
Span
>[
children:
<
Text
Span
>[
TextSpan
(
text:
'Second line!
\n
'
,
style:
TextStyle
(
...
...
@@ -439,7 +439,7 @@ void main() {
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.StrutForce.1.1.png'
),
);
},
skip:
true
);
// Should only be on linux (skip: !isLinux).
},
skip:
true
);
// Should only be on linux (skip: !
Platform.
isLinux).
// Disabled for now until font inconsistency is resolved.
testWidgets
(
'Decoration thickness'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -518,807 +518,4 @@ void main() {
matchesGoldenFile
(
'text_golden.DecorationThickness.1.0.png'
),
);
},
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
testWidgets
(
'Text Inline widget'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Center
(
child:
RepaintBoundary
(
child:
Material
(
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Container
(
width:
400.0
,
height:
200.0
,
decoration:
const
BoxDecoration
(
color:
Color
(
0xff00ff00
),
),
child:
ConstrainedBox
(
constraints:
const
BoxConstraints
(
minWidth:
0
,
maxWidth:
200
,
minHeight:
0
,
maxHeight:
100
),
child:
const
Text
.
rich
(
TextSpan
(
text:
'C '
,
style:
TextStyle
(
fontSize:
16
,
),
children:
<
InlineSpan
>[
WidgetSpan
(
child:
Checkbox
(
value:
true
,
onChanged:
null
),
),
WidgetSpan
(
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
TextSpan
(
text:
'He '
,
style:
TextStyle
(
fontSize:
20
)),
WidgetSpan
(
child:
SizedBox
(
width:
50.0
,
height:
55.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffffff00
),
),
child:
Center
(
child:
SizedBox
(
width:
10.0
,
height:
15.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffff0000
),
),
)
),
),
)
),
),
TextSpan
(
text:
'hello world! sieze the day!'
),
WidgetSpan
(
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
WidgetSpan
(
child:
SizedBox
(
width:
20
,
height:
20
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
)
),
WidgetSpan
(
child:
Checkbox
(
value:
false
,
onChanged:
null
),
alignment:
PlaceholderAlignment
.
baseline
,
baseline:
TextBaseline
.
alphabetic
),
WidgetSpan
(
child:
SizedBox
(
width:
20
,
height:
20
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
)
),
WidgetSpan
(
child:
Text
(
'embedded'
),
),
],
),
textDirection:
TextDirection
.
ltr
,
),
),
),
),
),
),
),
);
await
expectLater
(
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.TextInlineWidget.1.1.png'
),
);
},
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
testWidgets
(
'Text Inline widget textfield'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Center
(
child:
MaterialApp
(
home:
RepaintBoundary
(
child:
Material
(
child:
Container
(
width:
400.0
,
height:
200.0
,
decoration:
const
BoxDecoration
(
color:
Color
(
0xff00ff00
),
),
child:
ConstrainedBox
(
constraints:
const
BoxConstraints
(
minWidth:
0
,
maxWidth:
200
,
minHeight:
0
,
maxHeight:
100
),
child:
const
Text
.
rich
(
TextSpan
(
text:
'My name is: '
,
style:
TextStyle
(
fontSize:
20
,
),
children:
<
InlineSpan
>[
WidgetSpan
(
child:
SizedBox
(
width:
70
,
height:
25
,
child:
TextField
()),
),
TextSpan
(
text:
', and my favorite city is: '
,
style:
TextStyle
(
fontSize:
20
)),
WidgetSpan
(
child:
SizedBox
(
width:
70
,
height:
25
,
child:
TextField
()),
),
],
),
textDirection:
TextDirection
.
ltr
,
),
),
),
),
),
),
),
);
await
expectLater
(
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.TextInlineWidget.2.2.png'
),
);
},
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
// This tests if multiple Text.rich widgets are able to inline nest within each other.
testWidgets
(
'Text Inline widget nesting'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Center
(
child:
MaterialApp
(
home:
RepaintBoundary
(
child:
Material
(
child:
Container
(
width:
400.0
,
height:
200.0
,
decoration:
const
BoxDecoration
(
color:
Color
(
0xff00ff00
),
),
child:
ConstrainedBox
(
constraints:
const
BoxConstraints
(
minWidth:
0
,
maxWidth:
200
,
minHeight:
0
,
maxHeight:
100
),
child:
const
Text
.
rich
(
TextSpan
(
text:
'outer'
,
style:
TextStyle
(
fontSize:
20
,
),
children:
<
InlineSpan
>[
WidgetSpan
(
child:
Text
.
rich
(
TextSpan
(
text:
'inner'
,
style:
TextStyle
(
color:
Color
(
0xff402f4ff
)),
children:
<
InlineSpan
>[
WidgetSpan
(
child:
Text
.
rich
(
TextSpan
(
text:
'inner2'
,
style:
TextStyle
(
color:
Color
(
0xff003ffff
)),
children:
<
InlineSpan
>[
WidgetSpan
(
child:
SizedBox
(
width:
50.0
,
height:
55.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffffff30
),
),
child:
Center
(
child:
SizedBox
(
width:
10.0
,
height:
15.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xff5f00f0
),
),
)
),
),
)
),
),
],
),
),
),
WidgetSpan
(
child:
SizedBox
(
width:
50.0
,
height:
55.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xff5fff00
),
),
child:
Center
(
child:
SizedBox
(
width:
10.0
,
height:
15.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xff5f0000
),
),
)
),
),
)
),
),
],
),
),
),
TextSpan
(
text:
'outer'
,
style:
TextStyle
(
fontSize:
20
)),
WidgetSpan
(
child:
SizedBox
(
width:
70
,
height:
25
,
child:
TextField
()),
),
WidgetSpan
(
child:
SizedBox
(
width:
50.0
,
height:
55.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffff00ff
),
),
child:
Center
(
child:
SizedBox
(
width:
10.0
,
height:
15.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xff0000ff
),
),
)
),
),
)
),
),
],
),
textDirection:
TextDirection
.
ltr
,
),
),
),
),
),
),
),
);
await
expectLater
(
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.TextInlineWidgetNest.1.2.png'
),
);
},
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
testWidgets
(
'Text Inline widget baseline'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Center
(
child:
RepaintBoundary
(
child:
Material
(
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Container
(
width:
400.0
,
height:
200.0
,
decoration:
const
BoxDecoration
(
color:
Color
(
0xff00ff00
),
),
child:
ConstrainedBox
(
constraints:
const
BoxConstraints
(
minWidth:
0
,
maxWidth:
200
,
minHeight:
0
,
maxHeight:
100
),
child:
const
Text
.
rich
(
TextSpan
(
text:
'C '
,
style:
TextStyle
(
fontSize:
16
,
),
children:
<
InlineSpan
>[
WidgetSpan
(
alignment:
PlaceholderAlignment
.
baseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
),
WidgetSpan
(
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
TextSpan
(
text:
'He '
,
style:
TextStyle
(
fontSize:
20
)),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
baseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
50.0
,
height:
55.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffffff00
),
),
child:
Center
(
child:
SizedBox
(
width:
10.0
,
height:
15.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffff0000
),
),
)
),
),
)
),
),
TextSpan
(
text:
'hello world! sieze the day!'
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
baseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
baseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
20
,
height:
20
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
)
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
baseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
baseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
20
,
height:
20
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
)
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
baseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
Text
(
'embedded'
),
),
TextSpan
(
text:
'ref'
),
],
),
textDirection:
TextDirection
.
ltr
,
),
),
),
),
),
),
),
);
await
expectLater
(
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.TextInlineWidgetBaseline.1.1.png'
),
);
},
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
testWidgets
(
'Text Inline widget aboveBaseline'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Center
(
child:
RepaintBoundary
(
child:
Material
(
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Container
(
width:
400.0
,
height:
200.0
,
decoration:
const
BoxDecoration
(
color:
Color
(
0xff00ff00
),
),
child:
ConstrainedBox
(
constraints:
const
BoxConstraints
(
minWidth:
0
,
maxWidth:
200
,
minHeight:
0
,
maxHeight:
100
),
child:
const
Text
.
rich
(
TextSpan
(
text:
'C '
,
style:
TextStyle
(
fontSize:
16
,
),
children:
<
InlineSpan
>[
WidgetSpan
(
alignment:
PlaceholderAlignment
.
aboveBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
),
WidgetSpan
(
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
TextSpan
(
text:
'He '
,
style:
TextStyle
(
fontSize:
20
)),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
aboveBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
50.0
,
height:
55.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffffff00
),
),
child:
Center
(
child:
SizedBox
(
width:
10.0
,
height:
15.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffff0000
),
),
)
),
),
)
),
),
TextSpan
(
text:
'hello world! sieze the day!'
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
aboveBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
aboveBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
20
,
height:
20
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
)
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
aboveBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
aboveBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
20
,
height:
20
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
)
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
aboveBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
Text
(
'embedded'
),
),
TextSpan
(
text:
'ref'
),
],
),
textDirection:
TextDirection
.
ltr
,
),
),
),
),
),
),
),
);
await
expectLater
(
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.TextInlineWidgetAboveBaseline.1.1.png'
),
);
},
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
testWidgets
(
'Text Inline widget belowBaseline'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Center
(
child:
RepaintBoundary
(
child:
Material
(
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Container
(
width:
400.0
,
height:
200.0
,
decoration:
const
BoxDecoration
(
color:
Color
(
0xff00ff00
),
),
child:
ConstrainedBox
(
constraints:
const
BoxConstraints
(
minWidth:
0
,
maxWidth:
200
,
minHeight:
0
,
maxHeight:
100
),
child:
const
Text
.
rich
(
TextSpan
(
text:
'C '
,
style:
TextStyle
(
fontSize:
16
,
),
children:
<
InlineSpan
>[
WidgetSpan
(
alignment:
PlaceholderAlignment
.
belowBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
),
WidgetSpan
(
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
TextSpan
(
text:
'He '
,
style:
TextStyle
(
fontSize:
20
)),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
belowBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
50.0
,
height:
55.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffffff00
),
),
child:
Center
(
child:
SizedBox
(
width:
10.0
,
height:
15.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffff0000
),
),
)
),
),
)
),
),
TextSpan
(
text:
'hello world! sieze the day!'
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
belowBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
belowBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
20
,
height:
20
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
)
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
belowBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
belowBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
20
,
height:
20
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
)
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
belowBaseline
,
baseline:
TextBaseline
.
alphabetic
,
child:
Text
(
'embedded'
),
),
TextSpan
(
text:
'ref'
),
],
),
textDirection:
TextDirection
.
ltr
,
),
),
),
),
),
),
),
);
await
expectLater
(
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.TextInlineWidgetBelowBaseline.1.1.png'
),
);
},
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
testWidgets
(
'Text Inline widget top'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Center
(
child:
RepaintBoundary
(
child:
Material
(
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Container
(
width:
400.0
,
height:
200.0
,
decoration:
const
BoxDecoration
(
color:
Color
(
0xff00ff00
),
),
child:
ConstrainedBox
(
constraints:
const
BoxConstraints
(
minWidth:
0
,
maxWidth:
200
,
minHeight:
0
,
maxHeight:
100
),
child:
const
Text
.
rich
(
TextSpan
(
text:
'C '
,
style:
TextStyle
(
fontSize:
16
,
),
children:
<
InlineSpan
>[
WidgetSpan
(
alignment:
PlaceholderAlignment
.
top
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
),
WidgetSpan
(
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
TextSpan
(
text:
'He '
,
style:
TextStyle
(
fontSize:
20
)),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
top
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
50.0
,
height:
55.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffffff00
),
),
child:
Center
(
child:
SizedBox
(
width:
10.0
,
height:
15.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffff0000
),
),
)
),
),
)
),
),
TextSpan
(
text:
'hello world! sieze the day!'
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
top
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
top
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
20
,
height:
20
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
)
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
top
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
top
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
20
,
height:
20
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
)
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
top
,
baseline:
TextBaseline
.
alphabetic
,
child:
Text
(
'embedded'
),
),
TextSpan
(
text:
'ref'
),
],
),
textDirection:
TextDirection
.
ltr
,
),
),
),
),
),
),
),
);
await
expectLater
(
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.TextInlineWidgetTop.1.1.png'
),
);
},
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
testWidgets
(
'Text Inline widget middle'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
Center
(
child:
RepaintBoundary
(
child:
Material
(
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Container
(
width:
400.0
,
height:
200.0
,
decoration:
const
BoxDecoration
(
color:
Color
(
0xff00ff00
),
),
child:
ConstrainedBox
(
constraints:
const
BoxConstraints
(
minWidth:
0
,
maxWidth:
200
,
minHeight:
0
,
maxHeight:
100
),
child:
const
Text
.
rich
(
TextSpan
(
text:
'C '
,
style:
TextStyle
(
fontSize:
16
,
),
children:
<
InlineSpan
>[
WidgetSpan
(
alignment:
PlaceholderAlignment
.
middle
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
),
WidgetSpan
(
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
TextSpan
(
text:
'He '
,
style:
TextStyle
(
fontSize:
20
)),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
middle
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
50.0
,
height:
55.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffffff00
),
),
child:
Center
(
child:
SizedBox
(
width:
10.0
,
height:
15.0
,
child:
DecoratedBox
(
decoration:
BoxDecoration
(
color:
Color
(
0xffff0000
),
),
)
),
),
)
),
),
TextSpan
(
text:
'hello world! sieze the day!'
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
middle
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
middle
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
20
,
height:
20
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
)
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
middle
,
baseline:
TextBaseline
.
alphabetic
,
child:
Checkbox
(
value:
false
,
onChanged:
null
),
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
middle
,
baseline:
TextBaseline
.
alphabetic
,
child:
SizedBox
(
width:
20
,
height:
20
,
child:
Checkbox
(
value:
true
,
onChanged:
null
),
)
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
middle
,
baseline:
TextBaseline
.
alphabetic
,
child:
Text
(
'embedded'
),
),
TextSpan
(
text:
'ref'
),
],
),
textDirection:
TextDirection
.
ltr
,
),
),
),
),
),
),
),
);
await
expectLater
(
find
.
byType
(
Container
),
matchesGoldenFile
(
'text_golden.TextInlineWidgetMiddle.1.1.png'
),
);
},
skip:
!
isLinux
);
// Coretext uses different thicknesses for decoration
}
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/text_test.dart
View file @
4e5cf5ef
...
...
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/gestures.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/widgets.dart'
;
import
'../rendering/mock_canvas.dart'
;
import
'semantics_tester.dart'
;
...
...
@@ -294,140 +294,6 @@ void main() {
semantics
.
dispose
();
},
skip:
true
);
// TODO(jonahwilliams): correct once https://github.com/flutter/flutter/issues/20891 is resolved.
testWidgets
(
'inline widgets generate semantic nodes'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
const
TextStyle
textStyle
=
TextStyle
(
fontFamily:
'Ahem'
);
await
tester
.
pumpWidget
(
Text
.
rich
(
TextSpan
(
children:
<
InlineSpan
>[
const
TextSpan
(
text:
'a '
),
TextSpan
(
text:
'pebble'
,
recognizer:
TapGestureRecognizer
()..
onTap
=
()
{
}),
const
TextSpan
(
text:
' in the '
),
WidgetSpan
(
child:
SizedBox
(
width:
20
,
height:
40
,
child:
Card
(
child:
RichText
(
text:
const
TextSpan
(
text:
'INTERRUPTION'
),
textDirection:
TextDirection
.
rtl
,
),
),
),
),
const
TextSpan
(
text:
'sky'
),
],
style:
textStyle
,
),
textDirection:
TextDirection
.
ltr
,
),
);
final
TestSemantics
expectedSemantics
=
TestSemantics
.
root
(
children:
<
TestSemantics
>[
TestSemantics
.
rootChild
(
children:
<
TestSemantics
>[
TestSemantics
(
label:
'a '
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
'pebble'
,
textDirection:
TextDirection
.
ltr
,
actions:
<
SemanticsAction
>[
SemanticsAction
.
tap
,
],
),
TestSemantics
(
label:
' in the '
,
textDirection:
TextDirection
.
ltr
,
),
TestSemantics
(
label:
'INTERRUPTION'
,
textDirection:
TextDirection
.
rtl
,
),
TestSemantics
(
label:
'sky'
,
textDirection:
TextDirection
.
ltr
,
),
],
),
],
);
expect
(
semantics
,
hasSemantics
(
expectedSemantics
,
ignoreTransform:
true
,
ignoreId:
true
,
ignoreRect:
true
));
semantics
.
dispose
();
});
testWidgets
(
'inline widgets semantic nodes scale'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
const
TextStyle
textStyle
=
TextStyle
(
fontFamily:
'Ahem'
);
await
tester
.
pumpWidget
(
Text
.
rich
(
TextSpan
(
children:
<
InlineSpan
>[
const
TextSpan
(
text:
'a '
),
TextSpan
(
text:
'pebble'
,
recognizer:
TapGestureRecognizer
()..
onTap
=
()
{
}),
const
TextSpan
(
text:
' in the '
),
WidgetSpan
(
child:
SizedBox
(
width:
20
,
height:
40
,
child:
Card
(
child:
RichText
(
text:
const
TextSpan
(
text:
'INTERRUPTION'
),
textDirection:
TextDirection
.
rtl
,
),
),
),
),
const
TextSpan
(
text:
'sky'
),
],
style:
textStyle
,
),
textDirection:
TextDirection
.
ltr
,
textScaleFactor:
2
,
),
);
final
TestSemantics
expectedSemantics
=
TestSemantics
.
root
(
children:
<
TestSemantics
>[
TestSemantics
.
rootChild
(
rect:
const
Rect
.
fromLTRB
(
0.0
,
0.0
,
800.0
,
600.0
),
children:
<
TestSemantics
>[
TestSemantics
(
label:
'a '
,
textDirection:
TextDirection
.
ltr
,
rect:
const
Rect
.
fromLTRB
(-
4.0
,
48.0
,
60.0
,
84.0
),
),
TestSemantics
(
label:
'pebble'
,
textDirection:
TextDirection
.
ltr
,
actions:
<
SemanticsAction
>[
SemanticsAction
.
tap
,
],
rect:
const
Rect
.
fromLTRB
(
52.0
,
48.0
,
228.0
,
84.0
),
),
TestSemantics
(
label:
' in the '
,
textDirection:
TextDirection
.
ltr
,
rect:
const
Rect
.
fromLTRB
(
220.0
,
48.0
,
452.0
,
84.0
),
),
TestSemantics
(
label:
'INTERRUPTION'
,
textDirection:
TextDirection
.
rtl
,
rect:
const
Rect
.
fromLTRB
(
448.0
,
0.0
,
488.0
,
80.0
),
),
TestSemantics
(
label:
'sky'
,
textDirection:
TextDirection
.
ltr
,
rect:
const
Rect
.
fromLTRB
(
484.0
,
48.0
,
576.0
,
84.0
),
),
],
),
],
);
expect
(
semantics
,
hasSemantics
(
expectedSemantics
,
ignoreTransform:
true
,
ignoreId:
true
,));
semantics
.
dispose
();
});
testWidgets
(
'Overflow is clipping correctly - short text with overflow: clip'
,
(
WidgetTester
tester
)
async
{
await
_pumpTextWidget
(
...
...
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/widget_inspector_test.dart
View file @
4e5cf5ef
...
...
@@ -329,10 +329,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
}
// State type is private, hence using dynamic.
dynamic
getInspectorState
()
=>
inspectorKey
.
currentState
;
String
paragraphText
(
RenderParagraph
paragraph
)
{
final
TextSpan
textSpan
=
paragraph
.
text
;
return
textSpan
.
text
;
}
String
paragraphText
(
RenderParagraph
paragraph
)
=>
paragraph
.
text
.
text
;
await
tester
.
pumpWidget
(
Directionality
(
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment