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
779f5743
Commit
779f5743
authored
Aug 12, 2015
by
Collin Jackson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor of text rendering into painting layer
parent
d291fcae
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
188 additions
and
132 deletions
+188
-132
paragraph_painter.dart
packages/flutter/lib/painting/paragraph_painter.dart
+150
-0
paragraph.dart
packages/flutter/lib/rendering/paragraph.dart
+25
-120
basic.dart
packages/flutter/lib/widgets/basic.dart
+13
-12
No files found.
packages/flutter/lib/painting/paragraph_painter.dart
0 → 100644
View file @
779f5743
// 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:sky'
as
sky
;
import
'package:sky/painting/text_style.dart'
;
// This must be immutable, because we won't notice when it changes
abstract
class
TextSpan
{
sky
.
Node
_toDOM
(
sky
.
Document
owner
);
String
toString
([
String
prefix
=
''
]);
void
_applyStyleToContainer
(
sky
.
Element
container
)
{
}
}
class
PlainTextSpan
extends
TextSpan
{
PlainTextSpan
(
this
.
text
)
{
assert
(
text
!=
null
);
}
final
String
text
;
sky
.
Node
_toDOM
(
sky
.
Document
owner
)
{
return
owner
.
createText
(
text
);
}
bool
operator
==(
other
)
=>
other
is
PlainTextSpan
&&
text
==
other
.
text
;
int
get
hashCode
=>
text
.
hashCode
;
String
toString
([
String
prefix
=
''
])
=>
'
${prefix}${runtimeType}
: "
${text}
"'
;
}
class
StyledTextSpan
extends
TextSpan
{
StyledTextSpan
(
this
.
style
,
this
.
children
)
{
assert
(
style
!=
null
);
assert
(
children
!=
null
);
}
final
TextStyle
style
;
final
List
<
TextSpan
>
children
;
sky
.
Node
_toDOM
(
sky
.
Document
owner
)
{
sky
.
Element
parent
=
owner
.
createElement
(
't'
);
style
.
applyToCSSStyle
(
parent
.
style
);
for
(
TextSpan
child
in
children
)
{
parent
.
appendChild
(
child
.
_toDOM
(
owner
));
}
return
parent
;
}
void
_applyStyleToContainer
(
sky
.
Element
container
)
{
style
.
applyToContainerCSSStyle
(
container
.
style
);
}
bool
operator
==(
other
)
{
if
(
identical
(
this
,
other
))
return
true
;
if
(
other
is
!
StyledTextSpan
||
style
!=
other
.
style
||
children
.
length
!=
other
.
children
.
length
)
return
false
;
for
(
int
i
=
0
;
i
<
children
.
length
;
++
i
)
{
if
(
children
[
i
]
!=
other
.
children
[
i
])
return
false
;
}
return
true
;
}
int
get
hashCode
{
int
value
=
373
;
value
=
37
*
value
+
style
.
hashCode
;
for
(
TextSpan
child
in
children
)
value
=
37
*
value
+
child
.
hashCode
;
return
value
;
}
String
toString
([
String
prefix
=
''
])
{
List
<
String
>
result
=
[];
result
.
add
(
'
${prefix}${runtimeType}
:'
);
var
indent
=
'
${prefix}
'
;
result
.
add
(
'
${style.toString(indent)}
'
);
for
(
TextSpan
child
in
children
)
{
result
.
add
(
child
.
toString
(
indent
));
}
return
result
.
join
(
'
\n
'
);
}
}
class
ParagraphPainter
{
ParagraphPainter
(
TextSpan
text
)
{
_layoutRoot
.
rootElement
=
_document
.
createElement
(
'p'
);
assert
(
text
!=
null
);
this
.
text
=
text
;
}
final
sky
.
Document
_document
=
new
sky
.
Document
();
final
sky
.
LayoutRoot
_layoutRoot
=
new
sky
.
LayoutRoot
();
TextSpan
_text
;
TextSpan
get
text
=>
_text
;
void
set
text
(
TextSpan
value
)
{
_text
=
value
;
_layoutRoot
.
rootElement
.
setChild
(
_text
.
_toDOM
(
_document
));
_layoutRoot
.
rootElement
.
removeAttribute
(
'style'
);
_text
.
_applyStyleToContainer
(
_layoutRoot
.
rootElement
);
}
double
get
minWidth
=>
_layoutRoot
.
minWidth
;
void
set
minWidth
(
value
)
{
_layoutRoot
.
minWidth
=
value
;
}
double
get
maxWidth
=>
_layoutRoot
.
maxWidth
;
void
set
maxWidth
(
value
)
{
_layoutRoot
.
maxWidth
=
value
;
}
double
get
minHeight
=>
_layoutRoot
.
minHeight
;
void
set
minHeight
(
value
)
{
_layoutRoot
.
minHeight
=
value
;
}
double
get
maxHeight
=>
_layoutRoot
.
maxHeight
;
void
set
maxHeight
(
value
)
{
_layoutRoot
.
maxHeight
=
value
;
}
double
get
minContentWidth
=>
_layoutRoot
.
rootElement
.
minContentWidth
;
double
get
maxContentWidth
=>
_layoutRoot
.
rootElement
.
maxContentWidth
;
double
get
height
=>
_layoutRoot
.
rootElement
.
height
;
double
computeDistanceToActualBaseline
(
TextBaseline
baseline
)
{
sky
.
Element
root
=
_layoutRoot
.
rootElement
;
switch
(
baseline
)
{
case
TextBaseline
.
alphabetic
:
return
root
.
alphabeticBaseline
;
case
TextBaseline
.
ideographic
:
return
root
.
ideographicBaseline
;
}
}
void
layout
()
=>
_layoutRoot
.
layout
();
void
paint
(
sky
.
Canvas
canvas
,
sky
.
Offset
offset
)
{
// TODO(ianh): Make LayoutRoot support a paint offset so we don't
// need to translate for each span of text.
canvas
.
translate
(
offset
.
dx
,
offset
.
dy
);
_layoutRoot
.
paint
(
canvas
);
canvas
.
translate
(-
offset
.
dx
,
-
offset
.
dy
);
}
}
packages/flutter/lib/rendering/paragraph.dart
View file @
779f5743
...
...
@@ -2,92 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:sky'
as
sky
;
import
'package:sky/painting/text_style.dart'
;
import
'package:sky/painting/paragraph_painter.dart'
;
import
'package:sky/rendering/box.dart'
;
import
'package:sky/rendering/object.dart'
;
abstract
class
RenderInline
{
sky
.
Node
_toDOM
(
sky
.
Document
owner
);
String
toString
([
String
prefix
=
''
]);
void
_applyStyleToContainer
(
sky
.
Element
container
)
{
}
}
class
RenderText
extends
RenderInline
{
RenderText
(
this
.
text
)
{
assert
(
text
!=
null
);
}
final
String
text
;
sky
.
Node
_toDOM
(
sky
.
Document
owner
)
{
return
owner
.
createText
(
text
);
}
bool
operator
==(
other
)
=>
other
is
RenderText
&&
text
==
other
.
text
;
int
get
hashCode
=>
text
.
hashCode
;
String
toString
([
String
prefix
=
''
])
=>
'
${prefix}
InlineText: "
${text}
"'
;
}
class
RenderStyled
extends
RenderInline
{
RenderStyled
(
this
.
style
,
this
.
children
)
{
assert
(
style
!=
null
);
assert
(
children
!=
null
);
}
final
TextStyle
style
;
final
List
<
RenderInline
>
children
;
sky
.
Node
_toDOM
(
sky
.
Document
owner
)
{
sky
.
Element
parent
=
owner
.
createElement
(
't'
);
style
.
applyToCSSStyle
(
parent
.
style
);
for
(
RenderInline
child
in
children
)
{
parent
.
appendChild
(
child
.
_toDOM
(
owner
));
}
return
parent
;
}
void
_applyStyleToContainer
(
sky
.
Element
container
)
{
style
.
applyToContainerCSSStyle
(
container
.
style
);
}
bool
operator
==(
other
)
{
if
(
identical
(
this
,
other
))
return
true
;
if
(
other
is
!
RenderStyled
||
style
!=
other
.
style
||
children
.
length
!=
other
.
children
.
length
)
return
false
;
for
(
int
i
=
0
;
i
<
children
.
length
;
++
i
)
{
if
(
children
[
i
]
!=
other
.
children
[
i
])
return
false
;
}
return
true
;
}
int
get
hashCode
{
int
value
=
373
;
value
=
37
*
value
+
style
.
hashCode
;
for
(
RenderInline
child
in
children
)
value
=
37
*
value
+
child
.
hashCode
;
return
value
;
}
String
toString
([
String
prefix
=
''
])
{
List
<
String
>
result
=
[];
result
.
add
(
'
${prefix}
InlineStyle:'
);
var
indent
=
'
${prefix}
'
;
result
.
add
(
'
${style.toString(indent)}
'
);
for
(
RenderInline
child
in
children
)
{
result
.
add
(
child
.
toString
(
indent
));
}
return
result
.
join
(
'
\n
'
);
}
}
export
'package:sky/painting/paragraph_painter.dart'
show
TextSpan
,
PlainTextSpan
,
StyledTextSpan
;
// Unfortunately, using full precision floating point here causes bad layouts
// because floating point math isn't associative. If we add and subtract
...
...
@@ -102,25 +21,20 @@ double _applyFloatingPointHack(double layoutValue) {
class
RenderParagraph
extends
RenderBox
{
RenderParagraph
(
RenderInline
inline
)
{
_layoutRoot
.
rootElement
=
_document
.
createElement
(
'p'
);
this
.
inline
=
inline
;
RenderParagraph
(
TextSpan
text
)
:
_paragraphPainter
=
new
ParagraphPainter
(
text
)
{
assert
(
text
!=
null
)
;
}
final
sky
.
Document
_document
=
new
sky
.
Document
();
final
sky
.
LayoutRoot
_layoutRoot
=
new
sky
.
LayoutRoot
();
ParagraphPainter
_paragraphPainter
;
BoxConstraints
_constraintsForCurrentLayout
;
// when null, we don't have a current layout
RenderInline
_inline
;
RenderInline
get
inline
=>
_inline
;
void
set
inline
(
RenderInline
value
)
{
if
(
_inline
==
value
)
TextSpan
get
text
=>
_paragraphPainter
.
text
;
void
set
text
(
TextSpan
value
)
{
if
(
_paragraphPainter
.
text
==
value
)
return
;
_inline
=
value
;
_layoutRoot
.
rootElement
.
setChild
(
_inline
.
_toDOM
(
_document
));
_layoutRoot
.
rootElement
.
removeAttribute
(
'style'
);
_inline
.
_applyStyleToContainer
(
_layoutRoot
.
rootElement
);
_paragraphPainter
.
text
=
value
;
_constraintsForCurrentLayout
=
null
;
markNeedsLayout
();
}
...
...
@@ -129,30 +43,30 @@ class RenderParagraph extends RenderBox {
assert
(
constraints
!=
null
);
if
(
_constraintsForCurrentLayout
==
constraints
)
return
;
// already cached this layout
_
layoutRoot
.
maxWidth
=
constraints
.
maxWidth
;
_
layoutRoot
.
minWidth
=
constraints
.
minWidth
;
_
layoutRoot
.
minHeight
=
constraints
.
minHeight
;
_
layoutRoot
.
maxHeight
=
constraints
.
maxHeight
;
_
layoutRoot
.
layout
();
_
paragraphPainter
.
maxWidth
=
constraints
.
maxWidth
;
_
paragraphPainter
.
minWidth
=
constraints
.
minWidth
;
_
paragraphPainter
.
minHeight
=
constraints
.
minHeight
;
_
paragraphPainter
.
maxHeight
=
constraints
.
maxHeight
;
_
paragraphPainter
.
layout
();
_constraintsForCurrentLayout
=
constraints
;
}
double
getMinIntrinsicWidth
(
BoxConstraints
constraints
)
{
_layout
(
constraints
);
return
constraints
.
constrainWidth
(
_applyFloatingPointHack
(
_
layoutRoot
.
rootElement
.
minContentWidth
));
_applyFloatingPointHack
(
_
paragraphPainter
.
minContentWidth
));
}
double
getMaxIntrinsicWidth
(
BoxConstraints
constraints
)
{
_layout
(
constraints
);
return
constraints
.
constrainWidth
(
_applyFloatingPointHack
(
_
layoutRoot
.
rootElement
.
maxContentWidth
));
_applyFloatingPointHack
(
_
paragraphPainter
.
maxContentWidth
));
}
double
_getIntrinsicHeight
(
BoxConstraints
constraints
)
{
_layout
(
constraints
);
return
constraints
.
constrainHeight
(
_applyFloatingPointHack
(
_
layoutRoot
.
rootElement
.
height
));
_applyFloatingPointHack
(
_
paragraphPainter
.
height
));
}
double
getMinIntrinsicHeight
(
BoxConstraints
constraints
)
{
...
...
@@ -166,42 +80,33 @@ class RenderParagraph extends RenderBox {
double
computeDistanceToActualBaseline
(
TextBaseline
baseline
)
{
assert
(!
needsLayout
);
_layout
(
constraints
);
sky
.
Element
root
=
_layoutRoot
.
rootElement
;
switch
(
baseline
)
{
case
TextBaseline
.
alphabetic
:
return
root
.
alphabeticBaseline
;
case
TextBaseline
.
ideographic
:
return
root
.
ideographicBaseline
;
}
return
_paragraphPainter
.
computeDistanceToActualBaseline
(
baseline
);
}
void
performLayout
()
{
_layout
(
constraints
);
sky
.
Element
root
=
_layoutRoot
.
rootElement
;
// rootElement.width always expands to fill, use maxContentWidth instead.
size
=
constraints
.
constrain
(
new
Size
(
_applyFloatingPointHack
(
root
.
maxContentWidth
),
_applyFloatingPointHack
(
root
.
height
)));
// _paragraphPainter.width always expands to fill, use maxContentWidth instead.
size
=
constraints
.
constrain
(
new
Size
(
_applyFloatingPointHack
(
_paragraphPainter
.
maxContentWidth
),
_applyFloatingPointHack
(
_paragraphPainter
.
height
)));
}
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
// Ideally we could compute the min/max intrinsic width/height with a
// non-destructive operation. However, currently, computing these values
// will destroy state inside the
layout root
. If that happens, we need to
// will destroy state inside the
painter
. If that happens, we need to
// get back the correct state by calling _layout again.
//
// TODO(abarth): Make computing the min/max intrinsic width/height
// a non-destructive operation.
// TODO(ianh): Make LayoutRoot support a paint offset so we don't
// need to translate for each span of text.
_layout
(
constraints
);
context
.
canvas
.
translate
(
offset
.
dx
,
offset
.
dy
);
_layoutRoot
.
paint
(
context
.
canvas
);
context
.
canvas
.
translate
(-
offset
.
dx
,
-
offset
.
dy
);
_paragraphPainter
.
paint
(
context
.
canvas
,
offset
);
}
// we should probably expose a way to do precise (inter-glpyh) hit testing
String
debugDescribeSettings
(
String
prefix
)
{
String
result
=
'
${super.debugDescribeSettings(prefix)}
'
;
result
+=
'
${prefix}
inline:
\n
${inline
.toString("$prefix ")}
\n
'
;
result
+=
'
${prefix}
text:
\n
${text
.toString("$prefix ")}
\n
'
;
return
result
;
}
}
packages/flutter/lib/widgets/basic.dart
View file @
779f5743
...
...
@@ -10,6 +10,7 @@ import 'package:sky/base/image_resource.dart';
import
'package:sky/mojo/asset_bundle.dart'
;
import
'package:sky/mojo/net/image_cache.dart'
as
image_cache
;
import
'package:sky/painting/text_style.dart'
;
import
'package:sky/painting/paragraph_painter.dart'
;
import
'package:sky/rendering/block.dart'
;
import
'package:sky/rendering/box.dart'
;
import
'package:sky/rendering/flex.dart'
;
...
...
@@ -446,16 +447,16 @@ class Flexible extends ParentDataNode {
}
class
Paragraph
extends
LeafRenderObjectWrapper
{
Paragraph
({
Key
key
,
this
.
inline
})
:
super
(
key:
key
);
Paragraph
({
Key
key
,
this
.
text
})
:
super
(
key:
key
);
final
RenderInline
inline
;
final
TextSpan
text
;
RenderParagraph
createNode
()
=>
new
RenderParagraph
(
inline
);
RenderParagraph
createNode
()
=>
new
RenderParagraph
(
text
);
RenderParagraph
get
root
=>
super
.
root
;
void
syncRenderObject
(
Widget
old
)
{
super
.
syncRenderObject
(
old
);
root
.
inline
=
inline
;
root
.
text
=
text
;
}
}
...
...
@@ -464,25 +465,25 @@ class StyledText extends Component {
// Where "string" is text to display and text-style is an instance of
// TextStyle. The text-style applies to all of the elements that follow.
StyledText
({
this
.
elements
,
Key
key
})
:
super
(
key:
key
)
{
assert
(
_to
Inline
(
elements
)
!=
null
);
assert
(
_to
Span
(
elements
)
!=
null
);
}
final
dynamic
elements
;
RenderInline
_toInline
(
dynamic
element
)
{
TextSpan
_toSpan
(
dynamic
element
)
{
if
(
element
is
String
)
return
new
RenderText
(
element
);
return
new
PlainTextSpan
(
element
);
if
(
element
is
Iterable
)
{
dynamic
first
=
element
.
first
;
if
(
first
is
!
TextStyle
)
throw
new
ArgumentError
(
"First element of Iterable is a
${first.runtimeType}
not a TextStyle"
);
return
new
RenderStyled
(
first
,
element
.
skip
(
1
).
map
(
_toInline
).
toList
());
return
new
StyledTextSpan
(
first
,
element
.
skip
(
1
).
map
(
_toSpan
).
toList
());
}
throw
new
ArgumentError
(
"Element is
${element.runtimeType}
not a String or an Iterable"
);
}
Widget
build
()
{
return
new
Paragraph
(
inline:
_toInline
(
elements
));
return
new
Paragraph
(
text:
_toSpan
(
elements
));
}
}
...
...
@@ -493,7 +494,7 @@ class Text extends Component {
final
TextStyle
style
;
Widget
build
()
{
RenderInline
inline
=
new
RenderText
(
data
);
TextSpan
text
=
new
PlainTextSpan
(
data
);
TextStyle
defaultStyle
=
DefaultTextStyle
.
of
(
this
);
TextStyle
combinedStyle
;
if
(
defaultStyle
!=
null
)
{
...
...
@@ -505,8 +506,8 @@ class Text extends Component {
combinedStyle
=
style
;
}
if
(
combinedStyle
!=
null
)
inline
=
new
RenderStyled
(
combinedStyle
,
[
inline
]);
return
new
Paragraph
(
inline:
inline
);
text
=
new
StyledTextSpan
(
combinedStyle
,
[
text
]);
return
new
Paragraph
(
text:
text
);
}
}
...
...
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