LayoutTests/ChangeLog

 12007-03-01 Nikolas Zimmermann <zimmermann@kde.org>
 2
 3 Reviewed by NOBODY (OOPS!).
 4
 5 Add new svg use layout tests.
 6
 7 * svg/custom/struct-use-09-b.svg: Added.
 8 * svg/custom/use-nested-transform.svg: Added.
 9
1102007-03-01 Mitz Pettel <mitz@webkit.org>
211
312 Reviewed by Maciej.
19926

LayoutTests/svg/custom/struct-use-09-b.svg

 1<?xml version="1.0" encoding="UTF-8"?>
 2<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny-flat.dtd">
 3<svg version="1.1" baseProfile="basic" id="svg-root" width="100%" height="100%" viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 4 <!--======================================================================-->
 5 <!--= Copyright 2000 World Wide Web Consortium, (Massachusetts =-->
 6 <!--= Institute of Technology, Institut National de Recherche en =-->
 7 <!--= Informatique et en Automatique, Keio University). All Rights =-->
 8 <!--= Reserved. See http://www.w3.org/Consortium/Legal/. =-->
 9 <!--======================================================================-->
 10 <!-- NOTE: CVS will automatically update the -->
 11 <!-- "$RCSfile: struct-use-09-b.svg,v $" and "$Revision: 1.1 $" -->
 12 <!-- fields in the file. -->
 13 <!-- There is no need to update this information. -->
 14 <!-- =====================================================================-->
 15 <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/" reviewer="[reviewer]" owner="AN" desc="Tests the use element in symbol definition" status="created" version="$Revision: 1.1 $" testname="$RCSfile: struct-use-09-b.svg,v $">
 16 <OperatorScript>
 17 <Paragraph>
 18 This tests the use element inside a symbol definition. For the test to pass, 5 rectangles with a red stroke, nested in each other, must be rendered.
 19 </Paragraph>
 20 </OperatorScript>
 21 </SVGTestCase>
 22 <title id="test-title">$RCSfile: struct-use-09-b.svg,v $</title>
 23 <!--======================================================================-->
 24 <!--Content of Test Case follows... =====================-->
 25 <!--======================================================================-->
 26 <g id="test-body-content">
 27 <!-- put all of the actual test here -->
 28 <defs>
 29 <symbol id="rect1" overflow="visible">
 30 <rect x="-50" y="-50" width="100" height="100" fill="none" stroke="red" />
 31 </symbol>
 32 <symbol id="rect2" overflow="visible">
 33 <use xlink:href="#rect1" />
 34 <rect x="-52.5" y="-52.5" width="105" height="105" fill="none" stroke="red" />
 35 </symbol>
 36 <symbol id="rect3" overflow="visible">
 37 <use xlink:href="#rect2" />
 38 <rect x="-55" y="-55" width="110" height="110" fill="none" stroke="red" />
 39 </symbol>
 40 <symbol id="rect4" overflow="visible">
 41 <use xlink:href="#rect3" />
 42 <rect x="-57.5" y="-57.5" width="115" height="115" fill="none" stroke="red" />
 43 </symbol>
 44 <symbol id="rects" overflow="visible">
 45 <use xlink:href="#rect4" />
 46 <rect x="-60" y="-60" width="120" height="120" fill="none" stroke="red" />
 47 </symbol>
 48 </defs>
 49 <use x="240" y="180" xlink:href="#rects" />
 50 </g>
 51 <text id="revision" x="10" y="340" font-size="40" stroke="none" fill="black">$Revision: 1.1 $</text>
 52 <rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
 53 <g id="draft-watermark">
 54 <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
 55 <text font-family="'Arial Black', Arial, sans-serif" font-weight="bold" font-size="20" x="240"
 56 text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
 57 </g>
 58</svg>
0

LayoutTests/svg/custom/use-nested-transform.svg

 1<?xml version="1.0" standalone="no"?>
 2<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body" width="450" height="500" viewBox="0 0 450 500">
 3 <defs>
 4 <path id="Batik_Squiggle_Blue" fill="#6666FF" d="M172,44C137,60,31,135,11,199c-8,27,22,48,44,33
 5 C14,306-1,332,0,356c0,14,13,42,44,27c8-4,35-25,52-41
 6 c14-1,24-11,42-28c17,14,36,10,52-7c22,2,82-78,44-108
 7 c-3-24-30-37-53-18c-6-2-13-1-18,1c22-35,43-82,49-105
 8 C219,47,188,36,172,44z"/>
 9
 10 <g id="Batik_Tag_Box" >
 11 <rect x="1" y="1" width="446" height="496" style="fill:none; stroke:black" transform="translate(-418,-467)"/>
 12 <use xlink:href="#Batik_Squiggle_Blue" width="27" height="28" transform="translate(-418,-467)" />
 13 </g>
 14 </defs>
 15
 16 <use xlink:href="#Batik_Tag_Box" transform="translate(418,467)"/>
 17</svg>
0

WebCore/ChangeLog

 12007-03-01 Nikolas Zimmermann <zimmermann@kde.org>
 2
 3 Reviewed by NOBODY (OOPS!).
 4
 5 Fixes: http://bugs.webkit.org/show_bug.cgi?id=12936 (Master bug used to track all current use problems.)
 6
 7 Fixes: http://bugs.webkit.org/show_bug.cgi?id=12926 (transform attribute not respected in nested <use> elements)
 8 Fixes: http://bugs.webkit.org/show_bug.cgi?id=12267 (getElementById broken for <use>)
 9 Fixes: http://bugs.webkit.org/show_bug.cgi?id=12916 (use instance in symbol definition does not work)
 10 Fixes: http://bugs.webkit.org/show_bug.cgi?id=12917 (mouseout event does not occur after scaling use instance)
 11 Fixes: http://bugs.webkit.org/show_bug.cgi?id=12838 (SVG <use> DOM broken for script)
 12
 13 Added test: svg/custom/use-nested-transform.svg
 14 Added test: svg/custom/struct-use-09-b.svg (not yet official W3C-SVG-1.1 testcase)
 15 Fixes test: svg/custom/use-elementInstance-event-target.svg (rectangle now turns green on first click)
 16
 17 Fix all (except one) known <use> bug. The remaining bug (12630) is not crucical at all.
 18
 19 dom/Element.cpp needed following tweak: set hasParentStyle to true, if there is no parentNode
 20 available - which happens for <use> nodes, as it's a shadow node. This fixes recalcStyle behaviour.
 21 Override recalcStyle() in SVGUseElement, and properly forward the call to the shadow tree root element.
 22 The shadow tree now receives proper style updates (without having to recreate the whole tree!).
 23
 24 Override attributeChanged() in SVGUseElement and only call notifyAttributeChange if one of x/y/width/height/xlink:href
 25 attribute changed - otherwhise we'll end up recreating the tree for every transform/style/(non-existing-attribute) change.
 26
 27 Do not override transform in nested use situations, but correctly append (right-sided) the translation of the <use> element.
 28 Some cosmetic fixes: don't add transform="translate(0 0)" attributes if both x/y values are null in the shadow tree.
 29
 30 Factor out logic for replacing symbol/svg tags in the shadow tree, and also invoke it during expandUseElementsInShadowTree -
 31 otherwhise <symbol><use xlink:href="#someOtherSymbol"></symbol> the <use> gets expanded to a <symbol>. Though no one expands
 32 the <symbol> element - and we're end up in hitting an assertion. Avoid that.
 33
 34 * dom/Element.cpp:
 35 (WebCore::Element::recalcStyle):
 36 * ksvg2/svg/SVGUseElement.cpp:
 37 (WebCore::SVGUseElement::attributeChanged):
 38 (WebCore::SVGUseElement::notifyAttributeChange):
 39 (WebCore::SVGUseElement::recalcStyle):
 40 (WebCore::SVGUseElement::buildPendingResource):
 41 (WebCore::SVGUseElement::buildShadowTreeForSymbolTag):
 42 (WebCore::SVGUseElement::alterShadowTreeForSVGTag):
 43 (WebCore::SVGUseElement::buildShadowTree):
 44 (WebCore::SVGUseElement::expandUseElementsInShadowTree):
 45 (WebCore::SVGUseElement::attachShadowTree):
 46 * ksvg2/svg/SVGUseElement.h:
 47
1482007-03-01 Alexey Proskuryakov <ap@webkit.org>
249
350 Reviewed by Maciej.
19926

WebCore/dom/Element.cpp

@@void Element::recalcStyle(StyleChange ch
581581 // ### should go away and be done in renderobject
582582 RenderStyle* _style = renderStyle();
583583 bool hasParentStyle = parentNode() ? parentNode()->renderStyle() : false;
584 
 584
 585#if ENABLE(SVG)
 586 if (!hasParentStyle && isShadowNode() && isSVGElement())
 587 hasParentStyle = true;
 588#endif
 589
585590 if (hasParentStyle && (change >= Inherit || changed())) {
586591 RenderStyle *newStyle = document()->styleSelector()->styleForElement(this);
587592 StyleChange ch = diff(_style, newStyle);
19911

WebCore/ksvg2/svg/SVGUseElement.cpp

3333
3434#include "CString.h"
3535#include "Document.h"
 36#include "Event.h"
3637#include "HTMLNames.h"
3738#include "RenderSVGContainer.h"
3839#include "SVGElementInstance.h"

@@void SVGUseElement::removedFromDocument(
134135 m_shadowTreeRootElement = 0;
135136}
136137
 138void SVGUseElement::attributeChanged(Attribute* attr, bool preserveDecls)
 139{
 140 // Avoid calling SVGStyledElement::attributeChanged(), as it always calls notifyAttributeChange.
 141 SVGElement::attributeChanged(attr, preserveDecls);
 142
 143 if (!attached())
 144 return;
 145
 146 // Only update the tree if x/y/width/height or xlink:href changed.
 147 if (attr->name() == SVGNames::xAttr || attr->name() == SVGNames::yAttr ||
 148 attr->name() == SVGNames::widthAttr || attr->name() == SVGNames::heightAttr ||
 149 attr->name().matches(XLinkNames::hrefAttr))
 150 buildPendingResource();
 151 else if (m_shadowTreeRootElement)
 152 m_shadowTreeRootElement->setChanged();
 153}
 154
137155void SVGUseElement::notifyAttributeChange() const
138156{
139157 if (!attached())

@@void SVGUseElement::notifyAttributeChang
143161 // It has to be done correctly, by implementing attributeChanged().
144162 const_cast<SVGUseElement*>(this)->buildPendingResource();
145163
146  if (renderer())
147  renderer()->setNeedsLayout(true);
 164 if (m_shadowTreeRootElement)
 165 m_shadowTreeRootElement->setChanged();
 166}
 167
 168void SVGUseElement::recalcStyle(StyleChange change)
 169{
 170 SVGStyledElement::recalcStyle(change);
148171
149  SVGStyledElement::notifyAttributeChange();
 172 // The shadow tree root element is NOT a direct child element of us.
 173 // So we have to take care it receives style updates, manually.
 174 if (m_shadowTreeRootElement)
 175 m_shadowTreeRootElement->recalcStyle(change);
150176}
151177
152178#ifdef DUMP_INSTANCE_TREE

@@void SVGUseElement::buildPendingResource
226252
227253 // Setup shadow tree root node
228254 m_shadowTreeRootElement = new SVGGElement(SVGNames::gTag, document());
229  m_shadowTreeRootElement->setInDocument(true);
 255 m_shadowTreeRootElement->setInDocument();
230256 m_shadowTreeRootElement->setShadowParentNode(this);
231257
232258 // Spec: An additional transformation translate(x,y) is appended to the end
233259 // (i.e., right-side) of the transform attribute on the generated 'g', where x
234260 // and y represent the values of the x and y attributes on the 'use' element.
235  String transformString = String::format("translate(%f, %f)", x().value(), y().value());
236  m_shadowTreeRootElement->setAttribute(SVGNames::transformAttr, transformString);
 261 if (x().value() != 0.0 || y().value() != 0.0) {
 262 String transformString = String::format("translate(%f, %f)", x().value(), y().value());
 263 m_shadowTreeRootElement->setAttribute(SVGNames::transformAttr, transformString);
 264 }
237265
238266 // Build shadow tree from instance tree
239267 // This also handles the special cases: <use> on <symbol>, <use> on <svg>.

@@void SVGUseElement::handleDeepUseReferen
362390 buildInstanceTree(target, newInstance, foundCycle);
363391}
364392
365 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance)
 393PassRefPtr<SVGSVGElement> SVGUseElement::buildShadowTreeForSymbolTag(SVGElement* target, SVGElementInstance* targetInstance)
366394{
367395 ExceptionCode ec = 0;
368396
369397 String widthString = String::number(width().value());
370398 String heightString = String::number(height().value());
371399
372  if (target->hasTagName(SVGNames::symbolTag)) {
373  // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
374  // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
375  // always have explicit values for attributes width and height. If attributes width and/or
376  // height are provided on the 'use' element, then these attributes will be transferred to
377  // the generated 'svg'. If attributes width and/or height are not specified, the generated
378  // 'svg' element will use values of 100% for these attributes.
379  RefPtr<SVGSVGElement> svgElement = new SVGSVGElement(SVGNames::svgTag, document());
380 
381  // Transfer all attributes from <symbol> to the new <svg> element
382  *svgElement->attributes() = *target->attributes();
383 
384  // Explicitly re-set width/height values
385  svgElement->setAttribute(SVGNames::widthAttr, hasAttribute(SVGNames::widthAttr) ? widthString : "100%");
386  svgElement->setAttribute(SVGNames::heightAttr, hasAttribute(SVGNames::heightAttr) ? heightString : "100%");
387 
388  // Only clone symbol children, and add them to the new <svg> element
 400 // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
 401 // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
 402 // always have explicit values for attributes width and height. If attributes width and/or
 403 // height are provided on the 'use' element, then these attributes will be transferred to
 404 // the generated 'svg'. If attributes width and/or height are not specified, the generated
 405 // 'svg' element will use values of 100% for these attributes.
 406 RefPtr<SVGSVGElement> svgElement = new SVGSVGElement(SVGNames::svgTag, document());
 407
 408 // Transfer all attributes from <symbol> to the new <svg> element
 409 *svgElement->attributes() = *target->attributes();
 410
 411 // Explicitly re-set width/height values
 412 svgElement->setAttribute(SVGNames::widthAttr, hasAttribute(SVGNames::widthAttr) ? widthString : "100%");
 413 svgElement->setAttribute(SVGNames::heightAttr, hasAttribute(SVGNames::heightAttr) ? heightString : "100%");
 414
 415 // Only clone symbol children, and add them to the new <svg> element
 416 if (targetInstance) {
 417 // Called from buildShadowTree()
389418 for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling()) {
390419 RefPtr<Node> newChild = instance->correspondingElement()->cloneNode(true);
391420 svgElement->appendChild(newChild.release(), ec);
392421 ASSERT(ec == 0);
393422 }
 423 } else {
 424 // Called from expandUseElementsInShadowTree()
 425 for (Node* child = target->firstChild(); child; child = child->nextSibling()) {
 426 RefPtr<Node> newChild = child->cloneNode(true);
 427 svgElement->appendChild(newChild.release(), ec);
 428 ASSERT(ec == 0);
 429 }
 430 }
394431
395  m_shadowTreeRootElement->appendChild(svgElement.release(), ec);
396  ASSERT(ec == 0);
 432 return svgElement;
 433}
397434
398  return;
399  }
 435void SVGUseElement::alterShadowTreeForSVGTag(SVGElement* target)
 436{
 437 String widthString = String::number(width().value());
 438 String heightString = String::number(height().value());
 439
 440 if (hasAttribute(SVGNames::widthAttr))
 441 target->setAttribute(SVGNames::widthAttr, widthString);
 442
 443 if (hasAttribute(SVGNames::heightAttr))
 444 target->setAttribute(SVGNames::heightAttr, heightString);
 445}
 446
 447void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance)
 448{
 449 ExceptionCode ec = 0;
400450
401  // For all other target types, we just need to clone the whole referenced subtree.
402  RefPtr<Node> newChild = targetInstance->correspondingElement()->cloneNode(true);
 451 RefPtr<Node> newChild;
 452
 453 // Handle use referencing <symbol> special case
 454 if (target->hasTagName(SVGNames::symbolTag))
 455 newChild = buildShadowTreeForSymbolTag(target, targetInstance);
 456 else
 457 newChild = targetInstance->correspondingElement()->cloneNode(true);
403458
404459 SVGElement* newChildPtr = svg_dynamic_cast(newChild.get());
405460 ASSERT(newChildPtr);

@@void SVGUseElement::buildShadowTree(SVGE
408463 ASSERT(ec == 0);
409464
410465 // Handle use referencing <svg> special case
411  if (target->hasTagName(SVGNames::svgTag)) {
412  ASSERT(newChildPtr->hasTagName(SVGNames::svgTag));
413 
414  if (hasAttribute(SVGNames::widthAttr))
415  newChildPtr->setAttribute(SVGNames::widthAttr, widthString);
416 
417  if (hasAttribute(SVGNames::heightAttr))
418  newChildPtr->setAttribute(SVGNames::heightAttr, heightString);
419  }
 466 if (target->hasTagName(SVGNames::svgTag))
 467 alterShadowTreeForSVGTag(newChildPtr);
420468}
421469
422470void SVGUseElement::expandUseElementsInShadowTree(Node* element)

@@void SVGUseElement::expandUseElementsInS
437485
438486 // Don't ASSERT(target) here, it may be "pending", too.
439487 if (target) {
440  ExceptionCode ec = 0;
441 
442  // Clone whole target sub-tree
443  RefPtr<Node> clone = target->cloneNode(true);
444 
445488 // Setup sub-shadow tree root node
446489 RefPtr<SVGElement> cloneParent = new SVGGElement(SVGNames::gTag, document());
447490

@@void SVGUseElement::expandUseElementsInS
451494
452495 // Spec: An additional transformation translate(x,y) is appended to the end
453496 // (i.e., right-side) of the transform attribute on the generated 'g', where x
454  // and y represent the values of the x and y attributes on the 'use' element.
455  String transformString = String::format("translate(%f, %f)", use->x().value(), use->y().value());
456  cloneParent->setAttribute(SVGNames::transformAttr, transformString);
 497 // and y represent the values of the x and y attributes on the 'use' element.
 498 if (use->x().value() != 0.0 || use->y().value() != 0.0) {
 499 if (!cloneParent->hasAttribute(SVGNames::transformAttr)) {
 500 String transformString = String::format("translate(%f, %f)", use->x().value(), use->y().value());
 501 cloneParent->setAttribute(SVGNames::transformAttr, transformString);
 502 } else {
 503 String transformString = String::format(" translate(%f, %f)", use->x().value(), use->y().value());
 504 const AtomicString& transformAttribute = cloneParent->getAttribute(SVGNames::transformAttr);
 505 cloneParent->setAttribute(SVGNames::transformAttr, transformAttribute + transformString);
 506 }
 507 }
 508
 509 RefPtr<Node> newChild;
457510
458  cloneParent->appendChild(clone.release(), ec);
 511 // Handle use referencing <symbol> special case
 512 if (target->hasTagName(SVGNames::symbolTag))
 513 newChild = buildShadowTreeForSymbolTag(target, 0);
 514 else
 515 newChild = target->cloneNode(true);
 516
 517 SVGElement* newChildPtr = svg_dynamic_cast(newChild.get());
 518 ASSERT(newChildPtr);
 519
 520 ExceptionCode ec = 0;
 521 cloneParent->appendChild(newChild.release(), ec);
459522 ASSERT(ec == 0);
460523
461524 // Replace <use> with referenced content.

@@void SVGUseElement::expandUseElementsInS
463526 use->parentNode()->replaceChild(cloneParent.release(), use, ec);
464527 ASSERT(ec == 0);
465528
 529 // Handle use referencing <svg> special case
 530 if (target->hasTagName(SVGNames::svgTag))
 531 alterShadowTreeForSVGTag(newChildPtr);
 532
466533 // Immediately stop here, and restart expanding.
467534 expandUseElementsInShadowTree(m_shadowTreeRootElement.get());
468535 return;

@@void SVGUseElement::expandUseElementsInS
475542
476543void SVGUseElement::attachShadowTree()
477544{
478  if (!m_shadowTreeRootElement || !document()->shouldCreateRenderers() || !attached() || !renderer())
 545 if (!m_shadowTreeRootElement || m_shadowTreeRootElement->attached() || !document()->shouldCreateRenderers() || !attached() || !renderer())
479546 return;
480547
481  if (m_shadowTreeRootElement->attached())
482  m_shadowTreeRootElement->detach();
483 
484548 // Inspired by RenderTextControl::createSubtreeIfNeeded().
485549 if (renderer()->canHaveChildren() && childShouldCreateRenderer(m_shadowTreeRootElement.get())) {
486550 RenderStyle* style = m_shadowTreeRootElement->styleForRenderer(renderer());
487551
488552 if (m_shadowTreeRootElement->rendererIsNeeded(style)) {
489553 m_shadowTreeRootElement->setRenderer(m_shadowTreeRootElement->createRenderer(document()->renderArena(), style));
490  if (m_shadowTreeRootElement->renderer()) {
491  m_shadowTreeRootElement->renderer()->setStyle(style);
492  renderer()->addChild(m_shadowTreeRootElement->renderer(), m_shadowTreeRootElement->nextRenderer());
 554 if (RenderObject* shadowRenderer = m_shadowTreeRootElement->renderer()) {
 555 shadowRenderer->setStyle(style);
 556 renderer()->addChild(shadowRenderer, m_shadowTreeRootElement->nextRenderer());
493557
494558 // Mimic SVGStyledTransformableElement::attach() functionality
495559 SVGGElement* gElement = static_cast<SVGGElement*>(m_shadowTreeRootElement.get());
496  m_shadowTreeRootElement->renderer()->setLocalTransform(gElement->localMatrix());
 560 shadowRenderer->setLocalTransform(gElement->localMatrix());
497561
498562 m_shadowTreeRootElement->setAttached();
499563 }
19911

WebCore/ksvg2/svg/SVGUseElement.h

@@namespace WebCore
6060 virtual void parseMappedAttribute(MappedAttribute*);
6161 virtual void notifyAttributeChange() const;
6262
 63 virtual void attributeChanged(Attribute*, bool preserveDecls = false);
 64 virtual void recalcStyle(StyleChange = NoChange);
 65
6366 virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
6467 virtual void attach();
6568

@@namespace WebCore
8588 void handleDeepUseReferencing(SVGElement* use, SVGElementInstance* targetInstance, bool& foundCycle);
8689
8790 // Shadow tree handling
 91 PassRefPtr<SVGSVGElement> buildShadowTreeForSymbolTag(SVGElement* target, SVGElementInstance* targetInstance);
 92 void alterShadowTreeForSVGTag(SVGElement* target);
 93
8894 void buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance);
8995 void expandUseElementsInShadowTree(Node* element);
9096 void attachShadowTree();
19911