<marquee> support
David Hyatt
hyatt at apple.com
Wed Oct 29 01:00:58 CET 2003
I feel dirty. Evil. Bad. Nevertheless, here it is in all its hideous
glory.
-------------- next part --------------
Index: ChangeLog
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/ChangeLog,v
retrieving revision 1.2145
diff -u -p -r1.2145 ChangeLog
--- ChangeLog 2003/10/29 08:16:34 1.2145
+++ ChangeLog 2003/10/29 08:55:19
@@ -1,5 +1,128 @@
2003-10-29 David Hyatt <hyatt at apple.com>
+ Implement support for <marquee>. This includes support for the CSS3 specification (although modified a fair
+ bit to actually be compatible with WinIE's version and to correct obvious errors in the draft). All of the
+ marquee behaviors (slide, scroll, and alternate) are supported.
+
+ This patch also fixes the following bugs that were discovered while testing marquee:
+ (1) An error in the computation of scrollWidth and scrollHeight.
+ (2) The ability to ask for the leftmostPosition as well as the rightmostPosition of content and to
+ be able to ask for the positions of children (via left/right/lowest) without including the parent in the
+ computation.
+ (3) An optimization to RenderFlow's rightmost/lowestPosition functions to avoid examining text elements since
+ they are always fully accounted for by either overflow or by inline flow boxes.
+ (4) A fix for RTL rendering. A block with direction:RTL was being placed on the right, when in reality only
+ its children should be placed on the right.
+ (5) A fix to prevent inline blocks and tables from computing auto margins (making them just like floats in this
+ regard).
+
+ Reviewed by darin
+
+ * khtml/css/cssparser.cpp:
+ (validUnit):
+ (CSSParser::parseValue):
+ * khtml/css/cssproperties.c:
+ (hash_prop):
+ (findProp):
+ * khtml/css/cssproperties.h:
+ * khtml/css/cssproperties.in:
+ * khtml/css/cssstyleselector.cpp:
+ (khtml::convertToLength):
+ (khtml::CSSStyleSelector::applyRule):
+ * khtml/css/cssvalues.c:
+ (hash_val):
+ (findValue):
+ * khtml/css/cssvalues.h:
+ * khtml/css/cssvalues.in:
+ * khtml/css/html4.css:
+ * khtml/html/html_blockimpl.cpp:
+ (HTMLMarqueeElementImpl::HTMLMarqueeElementImpl):
+ (HTMLMarqueeElementImpl::id):
+ (HTMLMarqueeElementImpl::parseAttribute):
+ * khtml/html/html_blockimpl.h:
+ (DOM::HTMLMarqueeElementImpl::minimumDelay):
+ * khtml/html/htmlparser.cpp:
+ (KHTMLParser::getElement):
+ * khtml/misc/htmlattrs.c:
+ (hash_attr):
+ (findAttr):
+ * khtml/misc/htmlattrs.h:
+ * khtml/misc/htmlattrs.in:
+ * khtml/rendering/bidi.cpp:
+ (khtml::RenderBlock::findNextLineBreak):
+ * khtml/rendering/render_block.cpp:
+ (khtml::RenderBlock::lowestPosition):
+ (khtml::RenderBlock::rightmostPosition):
+ (khtml::RenderBlock::leftmostPosition):
+ * khtml/rendering/render_block.h:
+ * khtml/rendering/render_box.cpp:
+ (RenderBox::setStyle):
+ (RenderBox::calcWidth):
+ (RenderBox::calcHorizontalMargins):
+ (RenderBox::lowestPosition):
+ (RenderBox::rightmostPosition):
+ (RenderBox::leftmostPosition):
+ * khtml/rendering/render_box.h:
+ * khtml/rendering/render_flow.cpp:
+ (RenderFlow::lowestPosition):
+ (RenderFlow::rightmostPosition):
+ (RenderFlow::leftmostPosition):
+ * khtml/rendering/render_flow.h:
+ * khtml/rendering/render_layer.cpp:
+ (RenderLayer::RenderLayer):
+ (RenderLayer::~RenderLayer):
+ (RenderLayer::updateLayerPositions):
+ (RenderLayer::scrollToOffset):
+ (RenderLayer::computeScrollDimensions):
+ (RenderLayer::styleChanged):
+ (RenderLayer::stopMarquees):
+ (m_whiteSpace):
+ (Marquee::marqueeSpeed):
+ (Marquee::direction):
+ (Marquee::isHorizontal):
+ (Marquee::computePosition):
+ (Marquee::start):
+ (Marquee::stop):
+ (Marquee::updateMarqueePosition):
+ (Marquee::updateMarqueeStyle):
+ (Marquee::timerEvent):
+ * khtml/rendering/render_layer.h:
+ (khtml::):
+ (khtml::RenderLayer::marquee):
+ * khtml/rendering/render_object.cpp:
+ (RenderObject::isHTMLMarquee):
+ (RenderObject::sizesToMaxWidth):
+ * khtml/rendering/render_object.h:
+ (khtml::RenderObject::lowestPosition):
+ (khtml::RenderObject::rightmostPosition):
+ (khtml::RenderObject::leftmostPosition):
+ * khtml/rendering/render_style.cpp:
+ (StyleMarqueeData::StyleMarqueeData):
+ (StyleMarqueeData::operator==):
+ (opacity):
+ (marquee):
+ (StyleCSS3NonInheritedData::operator==):
+ (RenderStyle::RenderStyle):
+ * khtml/rendering/render_style.h:
+ (khtml::):
+ (khtml::StyleMarqueeData::operator!=):
+ (khtml::RenderStyle::marqueeIncrement):
+ (khtml::RenderStyle::marqueeSpeed):
+ (khtml::RenderStyle::marqueeLoopCount):
+ (khtml::RenderStyle::marqueeBehavior):
+ (khtml::RenderStyle::marqueeDirection):
+ (khtml::RenderStyle::setMarqueeIncrement):
+ (khtml::RenderStyle::setMarqueeSpeed):
+ (khtml::RenderStyle::setMarqueeDirection):
+ (khtml::RenderStyle::setMarqueeBehavior):
+ (khtml::RenderStyle::setMarqueeLoopCount):
+ * khtml/xml/dom_docimpl.cpp:
+ (DocumentImpl::createHTMLElement):
+ * kwq/KWQKHTMLPart.mm:
+ (KWQKHTMLPart::clearTimers):
+
+2003-10-29 David Hyatt <hyatt at apple.com>
+
Make <button> be an inline-block.
* khtml/css/html4.css:
Index: khtml/css/cssparser.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/css/cssparser.cpp,v
retrieving revision 1.44
diff -u -p -r1.44 khtml/css/cssparser.cpp
--- khtml/css/cssparser.cpp 2003/10/18 21:30:55 1.44
+++ khtml/css/cssparser.cpp 2003/10/29 08:55:22
@@ -378,11 +378,13 @@ static bool validUnit( Value *value, int
case CSSPrimitiveValue::CSS_PC:
b = (unitflags & FLength);
break;
+ case CSSPrimitiveValue::CSS_MS:
+ case CSSPrimitiveValue::CSS_S:
+ b = (unitflags & FTime);
+ break;
case CSSPrimitiveValue::CSS_DEG:
case CSSPrimitiveValue::CSS_RAD:
case CSSPrimitiveValue::CSS_GRAD:
- case CSSPrimitiveValue::CSS_MS:
- case CSSPrimitiveValue::CSS_S:
case CSSPrimitiveValue::CSS_HZ:
case CSSPrimitiveValue::CSS_KHZ:
case CSSPrimitiveValue::CSS_DIMENSION:
@@ -505,7 +507,8 @@ bool CSSParser::parseValue( int propId,
break;
case CSS_PROP_OVERFLOW: // visible | hidden | scroll | auto | inherit
- if ( id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO )
+ if (id == CSS_VAL_VISIBLE || id == CSS_VAL_HIDDEN || id == CSS_VAL_SCROLL || id == CSS_VAL_AUTO ||
+ id == CSS_VAL_MARQUEE)
valid_primitive = true;
break;
@@ -1029,6 +1032,42 @@ bool CSSParser::parseValue( int propId,
valid_primitive = validUnit(value, FInteger|FNonNeg, true);
break;
+ case CSS_PROP__KHTML_MARQUEE: {
+ const int properties[5] = { CSS_PROP__KHTML_MARQUEE_DIRECTION, CSS_PROP__KHTML_MARQUEE_INCREMENT,
+ CSS_PROP__KHTML_MARQUEE_REPETITION,
+ CSS_PROP__KHTML_MARQUEE_STYLE, CSS_PROP__KHTML_MARQUEE_SPEED };
+ return parseShortHand(properties, 5, important);
+ }
+ case CSS_PROP__KHTML_MARQUEE_DIRECTION:
+ if (id == CSS_VAL_FORWARDS || id == CSS_VAL_BACKWARDS || id == CSS_VAL_AHEAD ||
+ id == CSS_VAL_REVERSE || id == CSS_VAL_LEFT || id == CSS_VAL_RIGHT || id == CSS_VAL_DOWN ||
+ id == CSS_VAL_UP || id == CSS_VAL_AUTO)
+ valid_primitive = true;
+ break;
+ case CSS_PROP__KHTML_MARQUEE_INCREMENT:
+ if (id == CSS_VAL_SMALL || id == CSS_VAL_LARGE || id == CSS_VAL_MEDIUM)
+ valid_primitive = true;
+ else
+ valid_primitive = validUnit(value, FLength|FPercent, strict&(!nonCSSHint));
+ break;
+ case CSS_PROP__KHTML_MARQUEE_STYLE:
+ if (id == CSS_VAL_NONE || id == CSS_VAL_SLIDE || id == CSS_VAL_SCROLL || id == CSS_VAL_ALTERNATE)
+ valid_primitive = true;
+ break;
+ case CSS_PROP__KHTML_MARQUEE_REPETITION:
+ if (id == CSS_VAL_INFINITE)
+ valid_primitive = true;
+ else
+ valid_primitive = validUnit(value, FInteger|FNonNeg, strict&(!nonCSSHint));
+ break;
+ case CSS_PROP__KHTML_MARQUEE_SPEED:
+ if (id == CSS_VAL_NORMAL || id == CSS_VAL_SLOW || id == CSS_VAL_FAST)
+ valid_primitive = true;
+ else
+ valid_primitive = validUnit(value, FTime|FInteger|FNonNeg, strict&(!nonCSSHint));
+ break;
+ // End of CSS3 properties
+
/* shorthand properties */
case CSS_PROP_BACKGROUND:
// ['background-color' || 'background-image' ||'background-repeat' ||
Index: khtml/css/cssproperties.in
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/css/cssproperties.in,v
retrieving revision 1.8
diff -u -p -r1.8 khtml/css/cssproperties.in
--- khtml/css/cssproperties.in 2003/10/18 21:30:55 1.8
+++ khtml/css/cssproperties.in 2003/10/29 08:55:23
@@ -81,6 +81,12 @@ margin-right
margin-bottom
margin-left
marker-offset
+-khtml-marquee
+-khtml-marquee-direction
+-khtml-marquee-increment
+-khtml-marquee-repetition
+-khtml-marquee-speed
+-khtml-marquee-style
max-height
max-width
min-height
Index: khtml/css/cssstyleselector.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/css/cssstyleselector.cpp,v
retrieving revision 1.102
diff -u -p -r1.102 khtml/css/cssstyleselector.cpp
--- khtml/css/cssstyleselector.cpp 2003/10/21 22:14:37 1.102
+++ khtml/css/cssstyleselector.cpp 2003/10/29 08:55:27
@@ -2006,6 +2006,8 @@ void CSSStyleSelector::applyRule( int id
o = OSCROLL; break;
case CSS_VAL_AUTO:
o = OAUTO; break;
+ case CSS_VAL_MARQUEE:
+ o = OMARQUEE; break;
default:
return;
}
@@ -3387,7 +3389,145 @@ void CSSStyleSelector::applyRule( int id
if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
return; // Error case.
style->setBoxOrdinalGroup((unsigned int)(primitiveValue->getFloatValue(CSSPrimitiveValue::CSS_NUMBER)));
- return;
+ return;
+ case CSS_PROP__KHTML_MARQUEE:
+ if (value->cssValueType() != CSSValue::CSS_INHERIT || !parentNode) return;
+ style->setMarqueeDirection(parentStyle->marqueeDirection());
+ style->setMarqueeIncrement(parentStyle->marqueeIncrement());
+ style->setMarqueeSpeed(parentStyle->marqueeSpeed());
+ style->setMarqueeLoopCount(parentStyle->marqueeLoopCount());
+ style->setMarqueeBehavior(parentStyle->marqueeBehavior());
+ break;
+ case CSS_PROP__KHTML_MARQUEE_REPETITION: {
+ if (value->cssValueType() == CSSValue::CSS_INHERIT) {
+ if(!parentNode) return;
+ style->setMarqueeLoopCount(parentStyle->marqueeLoopCount());
+ return;
+ }
+ if (!primitiveValue) return;
+ if (primitiveValue->getIdent() == CSS_VAL_INFINITE)
+ style->setMarqueeLoopCount(-1); // -1 means repeat forever.
+ else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER)
+ style->setMarqueeLoopCount((int)(primitiveValue->getFloatValue(CSSPrimitiveValue::CSS_NUMBER)));
+ break;
+ }
+ case CSS_PROP__KHTML_MARQUEE_SPEED: {
+ if (value->cssValueType() == CSSValue::CSS_INHERIT) {
+ if(!parentNode) return;
+ style->setMarqueeSpeed(parentStyle->marqueeSpeed());
+ return;
+ }
+ if (!primitiveValue) return;
+ if (primitiveValue->getIdent()) {
+ switch (primitiveValue->getIdent())
+ {
+ case CSS_VAL_SLOW:
+ style->setMarqueeSpeed(500); // 500 msec.
+ break;
+ case CSS_VAL_NORMAL:
+ style->setMarqueeSpeed(85); // 85msec. The WinIE default.
+ break;
+ case CSS_VAL_FAST:
+ style->setMarqueeSpeed(10); // 10msec. Super fast.
+ break;
+ }
+ }
+ else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S)
+ style->setMarqueeSpeed(int(1000*primitiveValue->getFloatValue(CSSPrimitiveValue::CSS_S)));
+ else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_MS)
+ style->setMarqueeSpeed(int(primitiveValue->getFloatValue(CSSPrimitiveValue::CSS_MS)));
+ else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) // For scrollamount support.
+ style->setMarqueeSpeed(int(primitiveValue->getFloatValue(CSSPrimitiveValue::CSS_NUMBER)));
+ break;
+ }
+ case CSS_PROP__KHTML_MARQUEE_INCREMENT: {
+ if (value->cssValueType() == CSSValue::CSS_INHERIT) {
+ if(!parentNode) return;
+ style->setMarqueeIncrement(parentStyle->marqueeIncrement());
+ return;
+ }
+ if (!primitiveValue) return;
+ if (primitiveValue->getIdent()) {
+ switch (primitiveValue->getIdent())
+ {
+ case CSS_VAL_SMALL:
+ style->setMarqueeIncrement(Length(1, Fixed)); // 1px.
+ break;
+ case CSS_VAL_NORMAL:
+ style->setMarqueeIncrement(Length(6, Fixed)); // 6px. The WinIE default.
+ break;
+ case CSS_VAL_LARGE:
+ style->setMarqueeIncrement(Length(36, Fixed)); // 36px.
+ break;
+ }
+ }
+ else {
+ bool ok = true;
+ Length l = convertToLength(primitiveValue, style, paintDeviceMetrics, &ok);
+ if (ok)
+ style->setMarqueeIncrement(l);
+ }
+ break;
+ }
+ case CSS_PROP__KHTML_MARQUEE_STYLE: {
+ if (value->cssValueType() == CSSValue::CSS_INHERIT) {
+ if(!parentNode) return;
+ style->setMarqueeBehavior(parentStyle->marqueeBehavior());
+ return;
+ }
+ if (!primitiveValue || !primitiveValue->getIdent()) return;
+ switch (primitiveValue->getIdent())
+ {
+ case CSS_VAL_NONE:
+ style->setMarqueeBehavior(MNONE);
+ break;
+ case CSS_VAL_SCROLL:
+ style->setMarqueeBehavior(MSCROLL);
+ break;
+ case CSS_VAL_SLIDE:
+ style->setMarqueeBehavior(MSLIDE);
+ break;
+ case CSS_VAL_ALTERNATE:
+ style->setMarqueeBehavior(MALTERNATE);
+ break;
+ }
+ break;
+ }
+ case CSS_PROP__KHTML_MARQUEE_DIRECTION: {
+ if (value->cssValueType() == CSSValue::CSS_INHERIT) {
+ if(!parentNode) return;
+ style->setMarqueeDirection(parentStyle->marqueeDirection());
+ return;
+ }
+ if (!primitiveValue || !primitiveValue->getIdent()) return;
+ switch (primitiveValue->getIdent())
+ {
+ case CSS_VAL_FORWARDS:
+ style->setMarqueeDirection(MFORWARD);
+ break;
+ case CSS_VAL_BACKWARDS:
+ style->setMarqueeDirection(MBACKWARD);
+ break;
+ case CSS_VAL_AUTO:
+ style->setMarqueeDirection(MAUTO);
+ break;
+ case CSS_VAL_AHEAD:
+ case CSS_VAL_UP: // We don't support vertical languages, so AHEAD just maps to UP.
+ style->setMarqueeDirection(MUP);
+ break;
+ case CSS_VAL_REVERSE:
+ case CSS_VAL_DOWN: // REVERSE just maps to DOWN, since we don't do vertical text.
+ style->setMarqueeDirection(MDOWN);
+ break;
+ case CSS_VAL_LEFT:
+ style->setMarqueeDirection(MLEFT);
+ break;
+ case CSS_VAL_RIGHT:
+ style->setMarqueeDirection(MRIGHT);
+ break;
+ }
+ break;
+ }
default:
return;
}
Index: khtml/css/cssvalues.in
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/css/cssvalues.in,v
retrieving revision 1.11
diff -u -p -r1.11 khtml/css/cssvalues.in
--- khtml/css/cssvalues.in 2003/10/17 22:32:13 1.11
+++ khtml/css/cssvalues.in 2003/10/29 08:55:29
@@ -298,6 +298,7 @@ level
line-through
loud
lower
+marquee
mix
no-close-quote
no-open-quote
@@ -412,4 +413,29 @@ block-axis
# CSS_PROP_BOX_LINES
single
multiple
+
+# CSS_PROP_MARQUEE_DIRECTION
+forwards
+backwards
+ahead
+# reverse
+# left
+# right
+up
+down
+# auto
+
+# CSS_PROP_MARQUEE_SPEED
+slow
+# normal
+fast
+
+# CSS_PROP_MARQUEE_REPETITION
+infinite
+
+# CSS_PROP_MARQUEE_STYLE
+# none
+slide
+# scroll
+alternate
Index: khtml/css/html4.css
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/css/html4.css,v
retrieving revision 1.49
diff -u -p -r1.49 khtml/css/html4.css
--- khtml/css/html4.css 2003/10/29 08:16:34 1.49
+++ khtml/css/html4.css 2003/10/29 08:55:29
@@ -61,6 +61,11 @@ layer {
display: block;
}
+marquee {
+ display: inline-block;
+ overflow: marquee;
+}
+
address {
display: block;
}
@@ -489,10 +494,6 @@ nobr {
wbr {
white-space: normal;
-}
-
-marquee {
- display: none;
}
/* noscript is handled internally, as it depends on the html settings */
Index: khtml/html/html_blockimpl.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/html/html_blockimpl.cpp,v
retrieving revision 1.10
diff -u -p -r1.10 khtml/html/html_blockimpl.cpp
--- khtml/html/html_blockimpl.cpp 2003/07/24 22:07:45 1.10
+++ khtml/html/html_blockimpl.cpp 2003/10/29 08:55:31
@@ -233,6 +233,106 @@ void HTMLPreElementImpl::setWidth( long
// ###
}
+// -------------------------------------------------------------------------
+
+ // WinIE uses 60ms as the minimum delay by default.
+const int defaultMinimumDelay = 60;
+
+HTMLMarqueeElementImpl::HTMLMarqueeElementImpl(DocumentPtr *doc)
+: HTMLElementImpl(doc),
+ m_minimumDelay(defaultMinimumDelay)
+{
+}
+
+NodeImpl::Id HTMLMarqueeElementImpl::id() const
+{
+ return ID_MARQUEE;
+}
+
+void HTMLMarqueeElementImpl::parseAttribute(AttributeImpl *attr)
+{
+ switch(attr->id())
+ {
+ case ATTR_WIDTH:
+ if (!attr->value().isEmpty())
+ addCSSLength(CSS_PROP_WIDTH, attr->value());
+ else
+ removeCSSProperty(CSS_PROP_WIDTH);
+ break;
+ case ATTR_HEIGHT:
+ if (!attr->value().isEmpty())
+ addCSSLength(CSS_PROP_HEIGHT, attr->value());
+ else
+ removeCSSProperty(CSS_PROP_HEIGHT);
+ break;
+ case ATTR_BGCOLOR:
+ if (!attr->value().isEmpty())
+ addHTMLColor(CSS_PROP_BACKGROUND_COLOR, attr->value());
+ else
+ removeCSSProperty(CSS_PROP_BACKGROUND_COLOR);
+ break;
+ case ATTR_VSPACE:
+ if (!attr->value().isEmpty()) {
+ addCSSLength(CSS_PROP_MARGIN_TOP, attr->value());
+ addCSSLength(CSS_PROP_MARGIN_BOTTOM, attr->value());
+ }
+ else {
+ removeCSSProperty(CSS_PROP_MARGIN_TOP);
+ removeCSSProperty(CSS_PROP_MARGIN_BOTTOM);
+ }
+ break;
+ case ATTR_HSPACE:
+ if (!attr->value().isEmpty()) {
+ addCSSLength(CSS_PROP_MARGIN_LEFT, attr->value());
+ addCSSLength(CSS_PROP_MARGIN_RIGHT, attr->value());
+ }
+ else {
+ removeCSSProperty(CSS_PROP_MARGIN_LEFT);
+ removeCSSProperty(CSS_PROP_MARGIN_RIGHT);
+ }
+ break;
+ case ATTR_SCROLLAMOUNT:
+ if (!attr->value().isEmpty())
+ addCSSLength(CSS_PROP__KHTML_MARQUEE_INCREMENT, attr->value());
+ else
+ removeCSSProperty(CSS_PROP__KHTML_MARQUEE_INCREMENT);
+ break;
+ case ATTR_SCROLLDELAY:
+ if (!attr->value().isEmpty())
+ addCSSLength(CSS_PROP__KHTML_MARQUEE_SPEED, attr->value());
+ else
+ removeCSSProperty(CSS_PROP__KHTML_MARQUEE_SPEED);
+ break;
+ case ATTR_LOOP:
+ if (!attr->value().isEmpty()) {
+ if (attr->value() == "-1" || strcasecmp(attr->value(), "infinite") == 0)
+ addCSSProperty(CSS_PROP__KHTML_MARQUEE_REPETITION, CSS_VAL_INFINITE);
+ else
+ addCSSLength(CSS_PROP__KHTML_MARQUEE_REPETITION, attr->value());
+ }
+ else
+ removeCSSProperty(CSS_PROP__KHTML_MARQUEE_REPETITION);
+ break;
+ case ATTR_BEHAVIOR:
+ if (!attr->value().isEmpty())
+ addCSSProperty(CSS_PROP__KHTML_MARQUEE_STYLE, attr->value());
+ else
+ removeCSSProperty(CSS_PROP__KHTML_MARQUEE_STYLE);
+ break;
+ case ATTR_DIRECTION:
+ if (!attr->value().isEmpty())
+ addCSSProperty(CSS_PROP__KHTML_MARQUEE_DIRECTION, attr->value());
+ else
+ removeCSSProperty(CSS_PROP__KHTML_MARQUEE_DIRECTION);
+ break;
+ case ATTR_TRUESPEED:
+ m_minimumDelay = attr->val() ? 0 : defaultMinimumDelay;
+ break;
+ default:
+ HTMLElementImpl::parseAttribute(attr);
+ }
+}
+
// ------------------------------------------------------------------------
HTMLLayerElementImpl::HTMLLayerElementImpl(DocumentPtr *doc)
Index: khtml/html/html_blockimpl.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/html/html_blockimpl.h,v
retrieving revision 1.4
diff -u -p -r1.4 khtml/html/html_blockimpl.h
--- khtml/html/html_blockimpl.h 2002/12/05 01:20:08 1.4
+++ khtml/html/html_blockimpl.h 2003/10/29 08:55:31
@@ -112,6 +112,22 @@ public:
// -------------------------------------------------------------------------
+class HTMLMarqueeElementImpl : public HTMLElementImpl
+{
+public:
+ HTMLMarqueeElementImpl(DocumentPtr *doc);
+
+ virtual NodeImpl::Id id() const;
+ virtual void parseAttribute(AttributeImpl *token);
+
+ int minimumDelay() const { return m_minimumDelay; }
+
+private:
+ int m_minimumDelay;
+};
+
+// -------------------------------------------------------------------------
+
class HTMLLayerElementImpl : public HTMLDivElementImpl
{
public:
Index: khtml/html/htmlparser.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/html/htmlparser.cpp,v
retrieving revision 1.59
diff -u -p -r1.59 khtml/html/htmlparser.cpp
--- khtml/html/htmlparser.cpp 2003/10/06 20:28:50 1.59
+++ khtml/html/htmlparser.cpp 2003/10/29 08:55:33
@@ -1077,7 +1077,7 @@ NodeImpl *KHTMLParser::getElement(Token*
return 0;
break;
case ID_MARQUEE:
- n = new HTMLGenericElementImpl(document, t->id);
+ n = new HTMLMarqueeElementImpl(document);
break;
// text
case ID_TEXT:
Index: khtml/misc/htmlattrs.in
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/misc/htmlattrs.in,v
retrieving revision 1.4
diff -u -p -r1.4 khtml/misc/htmlattrs.in
--- khtml/misc/htmlattrs.in 2003/10/14 15:36:10 1.4
+++ khtml/misc/htmlattrs.in 2003/10/29 08:55:34
@@ -10,6 +10,7 @@ archive
autocomplete
axis
background
+behavior
bgcolor
bgproperties
border
@@ -40,6 +41,7 @@ datetime
declare
defer
dir
+direction
disabled
enctype
face
@@ -63,6 +65,7 @@ left
leftmargin
link
longdesc
+loop
marginheight
marginwidth
maxlength
@@ -115,6 +118,8 @@ rowspan
rules
scheme
scope
+scrollamount
+scrolldelay
scrolling
selected
shape
@@ -131,6 +136,7 @@ text
title
top
topmargin
+truespeed
type
unknown
usemap
Index: khtml/rendering/bidi.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/bidi.cpp,v
retrieving revision 1.77
diff -u -p -r1.77 khtml/rendering/bidi.cpp
--- khtml/rendering/bidi.cpp 2003/10/17 22:32:13 1.77
+++ khtml/rendering/bidi.cpp 2003/10/29 08:55:36
@@ -1577,7 +1577,23 @@ BidiIterator RenderBlock::findNextLineBr
tmpW += o->marginLeft()+o->borderLeft()+o->paddingLeft()+
o->marginRight()+o->borderRight()+o->paddingRight();
} else if ( o->isReplaced() ) {
- if (o->style()->whiteSpace() == NORMAL || last->style()->whiteSpace() == NORMAL) {
+ EWhiteSpace currWS = o->style()->whiteSpace();
+ EWhiteSpace lastWS = last->style()->whiteSpace();
+
+ // WinIE marquees have different whitespace characteristics by default when viewed from
+ // the outside vs. the inside. Text inside is NOWRAP, and so we altered the marquee's
+ // style to reflect this, but we now have to get back to the original whitespace value
+ // for the marquee when checking for line breaking.
+ if (o->isHTMLMarquee() && o->layer() && o->layer()->marquee())
+ currWS = o->layer()->marquee()->whiteSpace();
+ if (last->isHTMLMarquee() && last->layer() && last->layer()->marquee())
+ lastWS = last->layer()->marquee()->whiteSpace();
+
+ // Break on replaced elements if either has normal white-space.
+ // FIXME: This does not match WinIE, Opera, and Mozilla. They treat replaced elements
+ // like characters in a word, and require spaces between the replaced elements in order
+ // to break.
+ if (currWS == NORMAL || lastWS == NORMAL) {
w += tmpW;
tmpW = 0;
lBreak.obj = o;
Index: khtml/rendering/render_block.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_block.cpp,v
retrieving revision 1.70
diff -u -p -r1.70 khtml/rendering/render_block.cpp
--- khtml/rendering/render_block.cpp 2003/10/23 22:23:25 1.70
+++ khtml/rendering/render_block.cpp 2003/10/29 08:55:40
@@ -1586,12 +1586,12 @@ RenderBlock::floatBottom() const
}
int
-RenderBlock::lowestPosition(bool includeOverflowInterior) const
+RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
{
- int bottom = RenderFlow::lowestPosition(includeOverflowInterior);
+ int bottom = RenderFlow::lowestPosition(includeOverflowInterior, includeSelf);
if (!includeOverflowInterior && style()->hidesOverflow())
return bottom;
- if (m_overflowHeight > bottom)
+ if (includeSelf && m_overflowHeight > bottom)
bottom = m_overflowHeight;
if (m_floatingObjects) {
@@ -1600,7 +1600,7 @@ RenderBlock::lowestPosition(bool include
for ( ; (r = it.current()); ++it ) {
if (!r->noPaint) {
int lp = r->startY + r->node->lowestPosition(false);
- bottom = QMAX(bottom, lp);
+ bottom = kMax(bottom, lp);
}
}
}
@@ -1612,19 +1612,24 @@ RenderBlock::lowestPosition(bool include
QPtrListIterator<RenderObject> it(*m_positionedObjects);
for ( ; (r = it.current()); ++it ) {
int lp = r->yPos() + r->lowestPosition(false);
- bottom = QMAX(bottom, lp);
+ bottom = kMax(bottom, lp);
}
}
+ if (!includeSelf && lastLineBox()) {
+ int lp = lastLineBox()->yPos() + lastLineBox()->height();
+ bottom = kMax(bottom, lp);
+ }
+
return bottom;
}
-int RenderBlock::rightmostPosition(bool includeOverflowInterior) const
+int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
{
- int right = RenderFlow::rightmostPosition(includeOverflowInterior);
+ int right = RenderFlow::rightmostPosition(includeOverflowInterior, includeSelf);
if (!includeOverflowInterior && style()->hidesOverflow())
return right;
- if (m_overflowWidth > right)
+ if (includeSelf && m_overflowWidth > right)
right = m_overflowWidth;
if (m_floatingObjects) {
@@ -1633,7 +1638,7 @@ int RenderBlock::rightmostPosition(bool
for ( ; (r = it.current()); ++it ) {
if (!r->noPaint) {
int rp = r->left + r->node->rightmostPosition(false);
- right = QMAX(right, rp);
+ right = kMax(right, rp);
}
}
}
@@ -1643,13 +1648,55 @@ int RenderBlock::rightmostPosition(bool
QPtrListIterator<RenderObject> it(*m_positionedObjects);
for ( ; (r = it.current()); ++it ) {
int rp = r->xPos() + r->rightmostPosition(false);
- right = QMAX(right, rp);
+ right = kMax(right, rp);
}
}
+ if (!includeSelf && firstLineBox()) {
+ for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) {
+ int rp = currBox->xPos() + currBox->width();
+ right = kMax(right, rp);
+ }
+ }
+
return right;
}
+int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ int left = RenderFlow::leftmostPosition(includeOverflowInterior, includeSelf);
+ if (!includeOverflowInterior && style()->hidesOverflow())
+ return left;
+
+ // FIXME: Check left overflow when we eventually support it.
+
+ if (m_floatingObjects) {
+ FloatingObject* r;
+ QPtrListIterator<FloatingObject> it(*m_floatingObjects);
+ for ( ; (r = it.current()); ++it ) {
+ if (!r->noPaint) {
+ int lp = r->left + r->node->leftmostPosition(false);
+ left = kMin(left, lp);
+ }
+ }
+ }
+
+ if (m_positionedObjects && !isCanvas()) {
+ RenderObject* r;
+ QPtrListIterator<RenderObject> it(*m_positionedObjects);
+ for ( ; (r = it.current()); ++it ) {
+ int lp = r->xPos() + r->leftmostPosition(false);
+ left = kMin(left, lp);
+ }
+ }
+
+ if (!includeSelf && firstLineBox()) {
+ for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox())
+ left = kMin(left, (int)currBox->xPos());
+ }
+
+ return left;
+}
int
RenderBlock::leftBottom()
Index: khtml/rendering/render_block.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_block.h,v
retrieving revision 1.27
diff -u -p -r1.27 khtml/rendering/render_block.h
--- khtml/rendering/render_block.h 2003/10/23 22:23:25 1.27
+++ khtml/rendering/render_block.h 2003/10/29 08:55:40
@@ -151,8 +151,9 @@ public:
inline int rightBottom();
virtual unsigned short lineWidth(int y) const;
- virtual int lowestPosition(bool includeOverflowInterior=true) const;
- virtual int rightmostPosition(bool includeOverflowInterior=true) const;
+ virtual int lowestPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
+ virtual int rightmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
+ virtual int leftmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
int rightOffset() const;
int rightRelOffset(int y, int fixedOffset, bool applyTextIndent = true,
Index: khtml/rendering/render_box.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_box.cpp,v
retrieving revision 1.89
diff -u -p -r1.89 khtml/rendering/render_box.cpp
--- khtml/rendering/render_box.cpp 2003/10/22 02:22:21 1.89
+++ khtml/rendering/render_box.cpp 2003/10/29 08:55:42
@@ -108,6 +108,9 @@ void RenderBox::setStyle(RenderStyle *_s
m_layer = 0;
}
+ if (m_layer)
+ m_layer->styleChanged();
+
// Set the text color if we're the body.
if (isBody())
element()->getDocument()->setTextColor(_style->color());
@@ -753,7 +756,7 @@ void RenderBox::calcWidth()
if (cw && cw != m_width + m_marginLeft + m_marginRight && !isFloating() && !isInline() &&
!cb->isFlexibleBox())
{
- if (style()->direction()==LTR)
+ if (cb->style()->direction()==LTR)
m_marginRight = cw - m_width - m_marginLeft;
else
m_marginLeft = cw - m_width - m_marginRight;
@@ -802,7 +805,7 @@ int RenderBox::calcWidthUsing(WidthType
void RenderBox::calcHorizontalMargins(const Length& ml, const Length& mr, int cw)
{
- if (isFloating())
+ if (isFloating() || isInline()) // Inline blocks/tables and floats don't have their margins increased.
{
m_marginLeft = ml.minWidth(cw);
m_marginRight = mr.minWidth(cw);
@@ -1364,14 +1367,19 @@ void RenderBox::calcAbsoluteVertical()
}
-int RenderBox::lowestPosition(bool includeOverflowInterior) const
+int RenderBox::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
{
- return m_height;
+ return includeSelf ? m_height : 0;
}
-int RenderBox::rightmostPosition(bool includeOverflowInterior) const
+int RenderBox::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
{
- return m_width;
+ return includeSelf ? m_width : 0;
+}
+
+int RenderBox::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ return includeSelf ? 0 : m_width;
}
#undef DEBUG_LAYOUT
Index: khtml/rendering/render_box.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_box.h,v
retrieving revision 1.31
diff -u -p -r1.31 khtml/rendering/render_box.h
--- khtml/rendering/render_box.h 2003/10/09 00:45:35 1.31
+++ khtml/rendering/render_box.h 2003/10/29 08:55:42
@@ -84,8 +84,9 @@ public:
virtual void position(InlineBox* box, int from, int len, bool reverse);
- virtual int lowestPosition(bool includeOverflowInterior=true) const;
- virtual int rightmostPosition(bool includeOverflowInterior=true) const;
+ virtual int lowestPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
+ virtual int rightmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
+ virtual int leftmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
virtual QRect getAbsoluteRepaintRect();
virtual void computeAbsoluteRepaintRect(QRect& r, bool f=false);
Index: khtml/rendering/render_flow.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_flow.cpp,v
retrieving revision 1.112
diff -u -p -r1.112 khtml/rendering/render_flow.cpp
--- khtml/rendering/render_flow.cpp 2003/10/07 04:43:23 1.112
+++ khtml/rendering/render_flow.cpp 2003/10/29 08:55:43
@@ -268,9 +268,9 @@ QRect RenderFlow::getAbsoluteRepaintRect
}
int
-RenderFlow::lowestPosition(bool includeOverflowInterior) const
+RenderFlow::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
{
- int bottom = RenderBox::lowestPosition(includeOverflowInterior);
+ int bottom = RenderBox::lowestPosition(includeOverflowInterior, includeSelf);
if (!includeOverflowInterior && style()->hidesOverflow())
return bottom;
@@ -279,18 +279,18 @@ RenderFlow::lowestPosition(bool includeO
// a tiny rel div buried somewhere deep in our child tree. In this case we have to get to
// the abs div.
for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
- if (!c->isFloatingOrPositioned()) {
+ if (!c->isFloatingOrPositioned() && !c->isText()) {
int lp = c->yPos() + c->lowestPosition(false);
- bottom = QMAX(bottom, lp);
+ bottom = kMax(bottom, lp);
}
}
return bottom;
}
-int RenderFlow::rightmostPosition(bool includeOverflowInterior) const
+int RenderFlow::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
{
- int right = RenderBox::rightmostPosition(includeOverflowInterior);
+ int right = RenderBox::rightmostPosition(includeOverflowInterior, includeSelf);
if (!includeOverflowInterior && style()->hidesOverflow())
return right;
@@ -299,12 +299,32 @@ int RenderFlow::rightmostPosition(bool i
// a tiny rel div buried somewhere deep in our child tree. In this case we have to get to
// the abs div.
for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
- if (!c->isFloatingOrPositioned()) {
+ if (!c->isFloatingOrPositioned() && !c->isText()) {
int rp = c->xPos() + c->rightmostPosition(false);
- right = QMAX(right, rp);
+ right = kMax(right, rp);
}
}
return right;
+}
+
+int RenderFlow::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
+{
+ int left = RenderBox::leftmostPosition(includeOverflowInterior, includeSelf);
+ if (!includeOverflowInterior && style()->hidesOverflow())
+ return left;
+
+ // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
+ // For now, we have to descend into all the children, since we may have a huge abs div inside
+ // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to
+ // the abs div.
+ for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
+ if (!c->isFloatingOrPositioned() && !c->isText()) {
+ int lp = c->xPos() + c->leftmostPosition(false);
+ left = kMin(left, lp);
+ }
+ }
+
+ return left;
}
Index: khtml/rendering/render_flow.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_flow.h,v
retrieving revision 1.45
diff -u -p -r1.45 khtml/rendering/render_flow.h
--- khtml/rendering/render_flow.h 2003/10/01 20:58:55 1.45
+++ khtml/rendering/render_flow.h 2003/10/29 08:55:43
@@ -71,8 +71,9 @@ public:
virtual QRect getAbsoluteRepaintRect();
- virtual int lowestPosition(bool includeOverflowInterior=true) const;
- virtual int rightmostPosition(bool includeOverflowInterior=true) const;
+ virtual int lowestPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
+ virtual int rightmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
+ virtual int leftmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const;
protected:
// An inline can be split with blocks occurring in between the inline content.
Index: khtml/rendering/render_layer.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_layer.cpp,v
retrieving revision 1.54
diff -u -p -r1.54 khtml/rendering/render_layer.cpp
--- khtml/rendering/render_layer.cpp 2003/10/07 20:15:59 1.54
+++ khtml/rendering/render_layer.cpp 2003/10/29 08:55:45
@@ -48,6 +48,8 @@
#include "render_canvas.h"
#include "render_arena.h"
#include "xml/dom_docimpl.h"
+#include "misc/htmltags.h"
+#include "html/html_blockimpl.h"
#include <qscrollbar.h>
#include <qptrvector.h>
@@ -94,7 +96,8 @@ m_vBar( 0 ),
m_scrollMediator( 0 ),
m_posZOrderList( 0 ),
m_negZOrderList( 0 ),
-m_zOrderListsDirty( true )
+m_zOrderListsDirty( true ),
+m_marquee( 0 )
{
}
@@ -102,12 +105,12 @@ RenderLayer::~RenderLayer()
{
// Child layers will be deleted by their corresponding render objects, so
// our destructor doesn't have to do anything.
- m_parent = m_previous = m_next = m_first = m_last = 0;
delete m_hBar;
delete m_vBar;
delete m_scrollMediator;
delete m_posZOrderList;
delete m_negZOrderList;
+ delete m_marquee;
}
#ifdef INCREMENTAL_REPAINTING
@@ -147,7 +150,7 @@ void RenderLayer::updateLayerPositions()
QRect layerBounds = QRect(x,y,width(),height());
positionScrollbars(layerBounds);
}
-
+
// FIXME: Child object could override visibility.
if (checkForRepaint && (m_object->style()->visibility() == VISIBLE))
m_object->repaintAfterLayoutIfNeeded(m_repaintRect, m_fullRepaintRect);
@@ -159,6 +162,10 @@ void RenderLayer::updateLayerPositions()
#else
child->updateLayerPositions();
#endif
+
+ // With all our children positioned, now update our marquee if we need to.
+ if (m_marquee)
+ m_marquee->updateMarqueePosition();
}
void RenderLayer::updateLayerPosition()
@@ -421,19 +428,21 @@ RenderLayer::subtractScrollOffset(int& x
}
void
-RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars)
+RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint)
{
- if (x < 0) x = 0;
- if (y < 0) y = 0;
-
- // Call the scrollWidth/Height functions so that the dimensions will be computed if they need
- // to be (for overflow:hidden blocks).
- int maxX = scrollWidth() - m_object->clientWidth();
- int maxY = scrollHeight() - m_object->clientHeight();
+ if (renderer()->style()->overflow() != OMARQUEE) {
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+
+ // Call the scrollWidth/Height functions so that the dimensions will be computed if they need
+ // to be (for overflow:hidden blocks).
+ int maxX = scrollWidth() - m_object->clientWidth();
+ int maxY = scrollHeight() - m_object->clientHeight();
+
+ if (x > maxX) x = maxX;
+ if (y > maxY) y = maxY;
+ }
- if (x > maxX) x = maxX;
- if (y > maxY) y = maxY;
-
// FIXME: Eventually, we will want to perform a blit. For now never
// blit, since the check for blitting is going to be very
// complicated (since it will involve testing whether our layer
@@ -445,7 +454,8 @@ RenderLayer::scrollToOffset(int x, int y
// FIXME: Fire the onscroll DOM event.
// Just schedule a full repaint of our object.
- m_object->repaint(true);
+ if (repaint)
+ m_object->repaint(true);
if (updateScrollbars) {
if (m_hBar)
@@ -583,23 +593,20 @@ int RenderLayer::scrollHeight()
void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
{
m_scrollDimensionsDirty = false;
- int rightPos = m_object->rightmostPosition();
- int bottomPos = m_object->lowestPosition();
+
+ int rightPos = m_object->rightmostPosition(true, false) - m_object->borderLeft();
+ int bottomPos = m_object->lowestPosition(true, false) - m_object->borderTop();
int clientWidth = m_object->clientWidth();
int clientHeight = m_object->clientHeight();
- m_scrollWidth = clientWidth;
- m_scrollHeight = clientHeight;
- if (rightPos - m_object->borderLeft() > m_scrollWidth)
- m_scrollWidth = rightPos - m_object->borderLeft();
- if (bottomPos - m_object->borderTop() > m_scrollHeight)
- m_scrollHeight = bottomPos - m_object->borderTop();
+ m_scrollWidth = kMax(rightPos, clientWidth);
+ m_scrollHeight = kMax(bottomPos, clientHeight);
if (needHBar)
- *needHBar = rightPos > m_object->overflowWidth(false);
+ *needHBar = rightPos > clientWidth;
if (needVBar)
- *needVBar = bottomPos > m_object->overflowHeight(false);
+ *needVBar = bottomPos > clientHeight;
}
void
@@ -1179,3 +1186,254 @@ void RenderLayer::collectLayers(QPtrVect
child->collectLayers(posBuffer, negBuffer);
}
}
+
+void RenderLayer::styleChanged()
+{
+ if (m_object->style()->overflow() == OMARQUEE && m_object->style()->marqueeBehavior() != MNONE) {
+ if (!m_marquee)
+ m_marquee = new Marquee(this);
+ m_marquee->updateMarqueeStyle();
+ }
+ else if (m_marquee) {
+ delete m_marquee;
+ m_marquee = 0;
+ }
+}
+
+void RenderLayer::stopMarquees()
+{
+ if (m_marquee)
+ m_marquee->stop();
+
+ for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
+ curr->stopMarquees();
+}
+
+// --------------------------------------------------------------------------
+// Marquee implementation
+
+Marquee::Marquee(RenderLayer* l)
+:m_layer(l), m_currentLoop(0), m_timerId(0), m_start(0), m_end(0), m_speed(0), m_reset(false),
+ m_whiteSpace(NORMAL)
+{
+}
+
+int Marquee::marqueeSpeed() const
+{
+ int result = m_layer->renderer()->style()->marqueeSpeed();
+ DOM::NodeImpl* elt = m_layer->renderer()->element();
+ if (elt && elt->id() == ID_MARQUEE) {
+ HTMLMarqueeElementImpl* marqueeElt = static_cast<HTMLMarqueeElementImpl*>(elt);
+ result = kMax(result, marqueeElt->minimumDelay());
+ }
+ return result;
+}
+
+EMarqueeDirection Marquee::direction() const
+{
+ // FIXME: Support the CSS3 "auto" value for determining the direction of the marquee.
+ // For now just map MAUTO to MBACKWARD
+ EMarqueeDirection result = m_layer->renderer()->style()->marqueeDirection();
+ EDirection dir = m_layer->renderer()->style()->direction();
+ if (result == MAUTO)
+ result = MBACKWARD;
+ if (result == MFORWARD)
+ result = (dir == LTR) ? MRIGHT : MLEFT;
+ if (result == MBACKWARD)
+ result = (dir == LTR) ? MLEFT : MRIGHT;
+
+ // Now we have the real direction. Next we check to see if the increment is negative.
+ // If so, then we reverse the direction.
+ Length increment = m_layer->renderer()->style()->marqueeIncrement();
+ if (increment.value < 0)
+ result = static_cast<EMarqueeDirection>(-result);
+
+ return result;
+}
+
+bool Marquee::isHorizontal() const
+{
+ return direction() == MLEFT || direction() == MRIGHT;
+}
+
+int Marquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge)
+{
+ RenderObject* o = m_layer->renderer();
+ RenderStyle* s = o->style();
+ if (isHorizontal()) {
+ bool ltr = s->direction() == LTR;
+ int clientWidth = o->clientWidth();
+ int contentWidth = ltr ? o->rightmostPosition(true, false) : o->leftmostPosition(true, false);
+ if (ltr)
+ contentWidth += (o->paddingRight() - o->borderLeft());
+ else {
+ contentWidth = o->width() - contentWidth;
+ contentWidth += (o->paddingLeft() - o->borderRight());
+ }
+ if (dir == MRIGHT) {
+ if (stopAtContentEdge)
+ return kMax(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
+ else
+ return ltr ? contentWidth : clientWidth;
+ }
+ else {
+ if (stopAtContentEdge)
+ return kMin(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
+ else
+ return ltr ? -clientWidth : -contentWidth;
+ }
+ }
+ else {
+ int contentHeight = m_layer->renderer()->lowestPosition(true, false) -
+ m_layer->renderer()->borderTop() + m_layer->renderer()->paddingBottom();
+ int clientHeight = m_layer->renderer()->clientHeight();
+ if (dir == MUP) {
+ if (stopAtContentEdge)
+ return kMin(contentHeight - clientHeight, 0);
+ else
+ return -clientHeight;
+ }
+ else {
+ if (stopAtContentEdge)
+ return kMax(contentHeight - clientHeight, 0);
+ else
+ return contentHeight;
+ }
+ }
+}
+
+void Marquee::start()
+{
+ if (m_timerId)
+ return;
+
+ if (isHorizontal())
+ m_layer->scrollToOffset(m_start, 0, false, false);
+ else
+ m_layer->scrollToOffset(0, m_start, false, false);
+
+ m_timerId = startTimer(speed());
+}
+
+void Marquee::stop()
+{
+ m_currentLoop = 0;
+ m_reset = false;
+
+ if (m_timerId) {
+ killTimer(m_timerId);
+ m_timerId = 0;
+ }
+}
+
+void Marquee::updateMarqueePosition()
+{
+ bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
+ if (activate) {
+ EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior();
+ m_start = computePosition(direction(), behavior == MALTERNATE);
+ m_end = computePosition(reverseDirection(), behavior == MALTERNATE || behavior == MSLIDE);
+ start();
+ }
+}
+
+void Marquee::updateMarqueeStyle()
+{
+ RenderStyle* s = m_layer->renderer()->style();
+
+ m_totalLoops = s->marqueeLoopCount();
+ m_whiteSpace = s->whiteSpace();
+
+ if (m_layer->renderer()->isHTMLMarquee()) {
+ // Hack for WinIE. In WinIE, a value of 0 or lower for the loop count for SLIDE means to only do
+ // one loop.
+ if (m_totalLoops <= 0 && s->marqueeBehavior() == MSLIDE)
+ m_totalLoops = 1;
+
+ // Hack alert: Set the white-space value to nowrap for horizontal marquees with inline children, thus ensuring
+ // all the text ends up on one line by default. Limit this hack to the <marquee> element to emulate
+ // WinIE's behavior. Someone using CSS3 can use white-space: nowrap on their own to get this effect.
+ // Second hack alert: Set the text-align back to auto. WinIE completely ignores text-align on the
+ // marquee element.
+ // FIXME: Bring these up with the CSS WG.
+ if (isHorizontal() && m_layer->renderer()->childrenInline()) {
+ s->setWhiteSpace(NOWRAP);
+ s->setTextAlign(TAAUTO);
+ }
+ }
+
+ if (speed() != marqueeSpeed()) {
+ m_speed = marqueeSpeed();
+ if (m_timerId) {
+ killTimer(m_timerId);
+ m_timerId = startTimer(speed());
+ }
+ }
+
+ // Check the loop count to see if we should now stop.
+ bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
+ if (activate && !m_timerId)
+ m_layer->renderer()->setNeedsLayout(true);
+ else if (!activate && m_timerId) {
+ // Destroy the timer.
+ killTimer(m_timerId);
+ m_timerId = 0;
+ }
+}
+
+void Marquee::timerEvent(QTimerEvent* evt)
+{
+ if (m_layer->renderer()->needsLayout())
+ return;
+
+ if (m_reset) {
+ m_reset = false;
+ if (isHorizontal())
+ m_layer->scrollToXOffset(m_start);
+ else
+ m_layer->scrollToYOffset(m_start);
+ return;
+ }
+
+ RenderStyle* s = m_layer->renderer()->style();
+
+ int endPoint = m_end;
+ int range = m_end - m_start;
+ int newPos;
+ if (range == 0)
+ newPos = m_end;
+ else {
+ bool addIncrement = direction() == MUP || direction() == MLEFT;
+ if (s->marqueeBehavior() == MALTERNATE && m_currentLoop % 2) {
+ // We're going in the reverse direction.
+ endPoint = m_start;
+ range = -range;
+ addIncrement = !addIncrement;
+ }
+ bool positive = range > 0;
+ int clientSize = (isHorizontal() ? m_layer->renderer()->clientWidth() : m_layer->renderer()->clientHeight());
+ int increment = abs(m_layer->renderer()->style()->marqueeIncrement().width(clientSize));
+ newPos = (isHorizontal() ? m_layer->scrollXOffset() : m_layer->scrollYOffset()) +
+ (addIncrement ? increment : -increment);
+ if (positive)
+ newPos = kMin(newPos, endPoint);
+ else
+ newPos = kMax(newPos, endPoint);
+ }
+
+ if (newPos == endPoint) {
+ m_currentLoop++;
+ if (m_totalLoops > 0 && m_currentLoop >= m_totalLoops) {
+ killTimer(m_timerId);
+ m_timerId = 0;
+ }
+ else if (s->marqueeBehavior() != MALTERNATE)
+ m_reset = true;
+ }
+
+ if (isHorizontal())
+ m_layer->scrollToXOffset(newPos);
+ else
+ m_layer->scrollToYOffset(newPos);
+}
+
Index: khtml/rendering/render_layer.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_layer.h,v
retrieving revision 1.30
diff -u -p -r1.30 khtml/rendering/render_layer.h
--- khtml/rendering/render_layer.h 2003/10/07 20:15:59 1.30
+++ khtml/rendering/render_layer.h 2003/10/29 08:55:45
@@ -77,7 +77,44 @@ public:
private:
RenderLayer* m_layer;
};
+
+// This class handles the auto-scrolling of layers with overflow: marquee.
+class Marquee: public QObject
+{
+ Q_OBJECT
+
+public:
+ Marquee(RenderLayer* l);
+
+ void timerEvent(QTimerEvent*);
+
+ int speed() const { return m_speed; }
+ int marqueeSpeed() const;
+ EMarqueeDirection direction() const;
+ EMarqueeDirection reverseDirection() const { return static_cast<EMarqueeDirection>(-direction()); }
+ bool isHorizontal() const;
+ EWhiteSpace whiteSpace() { return m_whiteSpace; }
+
+ int computePosition(EMarqueeDirection dir, bool stopAtClientEdge);
+ void start();
+ void stop();
+
+ void updateMarqueeStyle();
+ void updateMarqueePosition();
+
+private:
+ RenderLayer* m_layer;
+ int m_currentLoop;
+ int m_totalLoops;
+ int m_timerId;
+ int m_start;
+ int m_end;
+ int m_speed;
+ bool m_reset;
+ EWhiteSpace m_whiteSpace : 2;
+};
+
class RenderLayer
{
public:
@@ -102,6 +139,11 @@ public:
void removeOnlyThisLayer();
void insertOnlyThisLayer();
+ void styleChanged();
+
+ Marquee* marquee() const { return m_marquee; }
+ void stopMarquees();
+
#if APPLE_CHANGES
bool isTransparent();
RenderLayer* transparentAncestor();
@@ -134,7 +176,7 @@ public:
void subtractScrollOffset(int& x, int& y);
short scrollXOffset() { return m_scrollX; }
int scrollYOffset() { return m_scrollY; }
- void scrollToOffset(int x, int y, bool updateScrollbars = true);
+ void scrollToOffset(int x, int y, bool updateScrollbars = true, bool repaint = true);
void scrollToXOffset(int x) { scrollToOffset(x, m_scrollY); }
void scrollToYOffset(int y) { scrollToOffset(m_scrollX, y); }
void setHasHorizontalScrollbar(bool hasScrollbar);
@@ -278,6 +320,8 @@ protected:
QPtrVector<RenderLayer>* m_posZOrderList;
QPtrVector<RenderLayer>* m_negZOrderList;
bool m_zOrderListsDirty;
+
+ Marquee* m_marquee; // Used by layers with overflow:marquee
};
}; // namespace
Index: khtml/rendering/render_object.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_object.cpp,v
retrieving revision 1.107
diff -u -p -r1.107 khtml/rendering/render_object.cpp
--- khtml/rendering/render_object.cpp 2003/10/23 22:23:25 1.107
+++ khtml/rendering/render_object.cpp 2003/10/29 08:55:47
@@ -170,6 +170,11 @@ bool RenderObject::isBody() const
return element() && element()->renderer() == this && element()->id() == ID_BODY;
}
+bool RenderObject::isHTMLMarquee() const
+{
+ return element() && element()->renderer() == this && element()->id() == ID_MARQUEE;
+}
+
bool RenderObject::canHaveChildren() const
{
return false;
@@ -560,10 +565,21 @@ int RenderObject::containingBlockHeight(
bool RenderObject::sizesToMaxWidth() const
{
- if (isFloating() || isCompact() || isInlineBlockOrInlineTable() ||
+ // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks,
+ // but they allow text to sit on the same line as the marquee.
+ if (isFloating() || isCompact() ||
+ (isInlineBlockOrInlineTable() && !isHTMLMarquee()) ||
(element() && (element()->id() == ID_BUTTON || element()->id() == ID_LEGEND)))
return true;
-
+
+ // Children of a horizontal marquee do not fill the container by default.
+ // FIXME: Need to deal with MAUTO value properly. It could be vertical.
+ if (parent()->style()->overflow() == OMARQUEE) {
+ EMarqueeDirection dir = parent()->style()->marqueeDirection();
+ if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
+ return true;
+ }
+
// Flexible horizontal boxes lay out children at their maxwidths. Also vertical boxes
// that don't stretch their kids lay out their children at their maxwidths.
if (parent()->isFlexibleBox() &&
Index: khtml/rendering/render_object.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_object.h,v
retrieving revision 1.88
diff -u -p -r1.88 khtml/rendering/render_object.h
--- khtml/rendering/render_object.h 2003/10/23 22:23:25 1.88
+++ khtml/rendering/render_object.h 2003/10/29 08:55:48
@@ -235,6 +235,8 @@ public:
virtual bool isFrameSet() const { return false; }
virtual bool isApplet() const { return false; }
+ bool isHTMLMarquee() const;
+
bool isAnonymous() const { return m_isAnonymous; }
void setIsAnonymous(bool b) { m_isAnonymous = b; }
@@ -638,14 +640,11 @@ public:
virtual void setSelectionState(SelectionState) {}
virtual void cursorPos(int /*offset*/, int &/*_x*/, int &/*_y*/, int &/*height*/);
-
- virtual int lowestPosition(bool includeOverflowInterior=true) const {return 0;}
-
- virtual int rightmostPosition(bool includeOverflowInterior=true) const {return 0;}
- // recursively invalidate current layout
- // unused: void invalidateLayout();
-
+ virtual int lowestPosition(bool includeOverflowInterior=true, bool includeSelf=true) const { return 0; }
+ virtual int rightmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const { return 0; }
+ virtual int leftmostPosition(bool includeOverflowInterior=true, bool includeSelf=true) const { return 0; }
+
virtual void calcVerticalMargins() {}
void removeFromObjectLists();
Index: khtml/rendering/render_style.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_style.cpp,v
retrieving revision 1.31
diff -u -p -r1.31 khtml/rendering/render_style.cpp
--- khtml/rendering/render_style.cpp 2003/10/23 22:23:25 1.31
+++ khtml/rendering/render_style.cpp 2003/10/29 08:55:49
@@ -129,6 +129,22 @@ bool StyleBackgroundData::operator==(con
outline == o.outline;
}
+StyleMarqueeData::StyleMarqueeData()
+{
+ increment.type = Fixed;
+ increment.value = 6; // 6 pixels is the WinIE default.
+ speed = 85; // 85msec is the WinIE default.
+ direction = MAUTO; // Direction is auto-determined by overflow by default.
+ behavior = MSCROLL; // Scrolling marquee is the default.
+ loops = -1; // Loop forever by default. Matches WinIE.
+}
+
+bool StyleMarqueeData::operator==(const StyleMarqueeData& o) const
+{
+ return (increment == o.increment && speed == o.speed && direction == o.direction &&
+ behavior == o.behavior && loops == o.loops);
+}
+
StyleFlexibleBoxData::StyleFlexibleBoxData()
: Shared<StyleFlexibleBoxData>()
{
@@ -166,17 +182,16 @@ bool StyleFlexibleBoxData::operator==(co
StyleCSS3NonInheritedData::StyleCSS3NonInheritedData()
:Shared<StyleCSS3NonInheritedData>(), opacity(1.0f)
{
-
}
StyleCSS3NonInheritedData::StyleCSS3NonInheritedData(const StyleCSS3NonInheritedData& o)
-:Shared<StyleCSS3NonInheritedData>(), opacity(o.opacity), flexibleBox(o.flexibleBox)
+:Shared<StyleCSS3NonInheritedData>(), opacity(o.opacity), flexibleBox(o.flexibleBox), marquee(o.marquee)
{
}
bool StyleCSS3NonInheritedData::operator==(const StyleCSS3NonInheritedData& o) const
{
- return opacity == o.opacity && flexibleBox == o.flexibleBox;
+ return opacity == o.opacity && flexibleBox == o.flexibleBox && marquee == o.marquee;
}
StyleCSS3InheritedData::StyleCSS3InheritedData()
@@ -273,6 +288,7 @@ RenderStyle::RenderStyle(bool)
surround.init();
css3NonInheritedData.init();
css3NonInheritedData.access()->flexibleBox.init();
+ css3NonInheritedData.access()->marquee.init();
css3InheritedData.init();
inherited.init();
Index: khtml/rendering/render_style.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_style.h,v
retrieving revision 1.34
diff -u -p -r1.34 khtml/rendering/render_style.h
--- khtml/rendering/render_style.h 2003/10/23 22:23:25 1.34
+++ khtml/rendering/render_style.h 2003/10/29 08:55:51
@@ -323,7 +323,7 @@ public:
// Random visual rendering model attributes. Not inherited.
enum EOverflow {
- OVISIBLE, OHIDDEN, OSCROLL, OAUTO
+ OVISIBLE, OHIDDEN, OSCROLL, OAUTO, OMARQUEE
};
enum EVerticalAlign {
@@ -404,6 +404,31 @@ public:
};
//------------------------------------------------
+// CSS3 Marquee Properties
+
+enum EMarqueeBehavior { MNONE, MSCROLL, MSLIDE, MALTERNATE };
+enum EMarqueeDirection { MAUTO = 0, MLEFT = 1, MRIGHT = -1, MUP = 2, MDOWN = -2, MFORWARD = 3, MBACKWARD = -3 };
+
+class StyleMarqueeData : public Shared<StyleMarqueeData>
+{
+public:
+ StyleMarqueeData();
+
+ bool operator==(const StyleMarqueeData& o) const;
+ bool operator!=(const StyleMarqueeData& o) const {
+ return !(*this == o);
+ }
+
+ Length increment;
+ int speed;
+
+ int loops; // -1 means infinite.
+
+ EMarqueeBehavior behavior : 2;
+ EMarqueeDirection direction : 3;
+};
+
+//------------------------------------------------
// CSS3 Flexible Box Properties
enum EBoxAlignment { BSTRETCH, BSTART, BCENTER, BEND, BJUSTIFY, BBASELINE };
@@ -471,6 +496,7 @@ public:
float opacity; // Whether or not we're transparent.
DataRef<StyleFlexibleBoxData> flexibleBox; // Flexible box properties
+ DataRef<StyleMarqueeData> marquee; // Marquee properties
};
// This struct is for rarely used inherited CSS3 properties. By grouping them together,
@@ -949,6 +975,11 @@ public:
EBoxOrient boxOrient() { return css3NonInheritedData->flexibleBox->orient; }
EBoxAlignment boxPack() { return css3NonInheritedData->flexibleBox->pack; }
int boxFlexedHeight() { return css3NonInheritedData->flexibleBox->flexed_height; }
+ Length marqueeIncrement() { return css3NonInheritedData->marquee->increment; }
+ int marqueeSpeed() { return css3NonInheritedData->marquee->speed; }
+ int marqueeLoopCount() { return css3NonInheritedData->marquee->loops; }
+ EMarqueeBehavior marqueeBehavior() { return css3NonInheritedData->marquee->behavior; }
+ EMarqueeDirection marqueeDirection() { return css3NonInheritedData->marquee->direction; }
// End CSS3 Getters
// attribute setter methods
@@ -1106,6 +1137,11 @@ public:
void setBoxOrient(EBoxOrient o) { SET_VAR(css3NonInheritedData.access()->flexibleBox, orient, o); }
void setBoxPack(EBoxAlignment p) { SET_VAR(css3NonInheritedData.access()->flexibleBox, pack, p); }
void setBoxFlexedHeight(int h) { SET_VAR(css3NonInheritedData.access()->flexibleBox, flexed_height, h); }
+ void setMarqueeIncrement(const Length& f) { SET_VAR(css3NonInheritedData.access()->marquee, increment, f); }
+ void setMarqueeSpeed(int f) { SET_VAR(css3NonInheritedData.access()->marquee, speed, f); }
+ void setMarqueeDirection(EMarqueeDirection d) { SET_VAR(css3NonInheritedData.access()->marquee, direction, d); }
+ void setMarqueeBehavior(EMarqueeBehavior b) { SET_VAR(css3NonInheritedData.access()->marquee, behavior, b); }
+ void setMarqueeLoopCount(int i) { SET_VAR(css3NonInheritedData.access()->marquee, loops, i); }
// End CSS3 Setters
QPalette palette() const { return visual->palette; }
Index: khtml/xml/dom_docimpl.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/xml/dom_docimpl.cpp,v
retrieving revision 1.83
diff -u -p -r1.83 khtml/xml/dom_docimpl.cpp
--- khtml/xml/dom_docimpl.cpp 2003/10/20 17:28:10 1.83
+++ khtml/xml/dom_docimpl.cpp 2003/10/29 08:55:53
@@ -850,6 +850,10 @@ ElementImpl *DocumentImpl::createHTMLEle
n = new HTMLGenericElementImpl(docPtr(), id);
break;
+ case ID_MARQUEE:
+ n = new HTMLMarqueeElementImpl(docPtr());
+ break;
+
case ID_BDO:
break;
Index: kwq/KWQKHTMLPart.mm
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/kwq/KWQKHTMLPart.mm,v
retrieving revision 1.418
diff -u -p -r1.418 kwq/KWQKHTMLPart.mm
--- kwq/KWQKHTMLPart.mm 2003/10/29 07:22:09 1.418
+++ kwq/KWQKHTMLPart.mm 2003/10/29 08:55:57
@@ -1726,8 +1726,14 @@ void KWQKHTMLPart::khtmlMouseReleaseEven
void KWQKHTMLPart::clearTimers(KHTMLView *view)
{
- if (view)
+ if (view) {
view->unscheduleRelayout();
+ if (view->part()) {
+ DocumentImpl* document = view->part()->xmlDocImpl();
+ if (document && document->renderer() && document->renderer()->layer())
+ document->renderer()->layer()->stopMarquees();
+ }
+ }
}
void KWQKHTMLPart::clearTimers()
-------------- next part --------------
dave
More information about the Khtml-devel
mailing list