1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4 *           (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2003, 2010 Apple Inc. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB.  If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23#include "config.h"
24#include "HTMLTitleElement.h"
25
26#include "Document.h"
27#include "HTMLNames.h"
28#include "NodeRenderStyle.h"
29#include "RenderStyle.h"
30#include "StyleInheritedData.h"
31#include "StyleResolver.h"
32#include "Text.h"
33#include "TextNodeTraversal.h"
34#include <wtf/Ref.h>
35#include <wtf/text/StringBuilder.h>
36
37namespace WebCore {
38
39using namespace HTMLNames;
40
41inline HTMLTitleElement::HTMLTitleElement(const QualifiedName& tagName, Document& document)
42    : HTMLElement(tagName, document)
43{
44    ASSERT(hasTagName(titleTag));
45}
46
47PassRefPtr<HTMLTitleElement> HTMLTitleElement::create(const QualifiedName& tagName, Document& document)
48{
49    return adoptRef(new HTMLTitleElement(tagName, document));
50}
51
52Node::InsertionNotificationRequest HTMLTitleElement::insertedInto(ContainerNode& insertionPoint)
53{
54    HTMLElement::insertedInto(insertionPoint);
55    if (inDocument() && !isInShadowTree())
56        document().setTitleElement(m_title, this);
57    return InsertionDone;
58}
59
60void HTMLTitleElement::removedFrom(ContainerNode& insertionPoint)
61{
62    HTMLElement::removedFrom(insertionPoint);
63    if (insertionPoint.inDocument() && !insertionPoint.isInShadowTree())
64        document().removeTitle(this);
65}
66
67void HTMLTitleElement::childrenChanged(const ChildChange& change)
68{
69    HTMLElement::childrenChanged(change);
70    m_title = textWithDirection();
71    if (inDocument()) {
72        if (!isInShadowTree())
73            document().setTitleElement(m_title, this);
74        else
75            document().removeTitle(this);
76    }
77}
78
79String HTMLTitleElement::text() const
80{
81    return TextNodeTraversal::contentsAsString(this);
82}
83
84StringWithDirection HTMLTitleElement::textWithDirection()
85{
86    TextDirection direction = LTR;
87    if (RenderStyle* computedStyle = this->computedStyle())
88        direction = computedStyle->direction();
89    else {
90        Ref<RenderStyle> style(document().ensureStyleResolver().styleForElement(this, parentElement() ? parentElement()->renderStyle() : nullptr));
91        direction = style.get().direction();
92    }
93    return StringWithDirection(text(), direction);
94}
95
96void HTMLTitleElement::setText(const String &value)
97{
98    Ref<HTMLTitleElement> protectFromMutationEvents(*this);
99
100    int numChildren = childNodeCount();
101
102    if (numChildren == 1 && firstChild()->isTextNode())
103        toText(firstChild())->setData(value, IGNORE_EXCEPTION);
104    else {
105        // We make a copy here because entity of "value" argument can be Document::m_title,
106        // which goes empty during removeChildren() invocation below,
107        // which causes HTMLTitleElement::childrenChanged(), which ends up Document::setTitle().
108        String valueCopy(value);
109
110        if (numChildren > 0)
111            removeChildren();
112
113        appendChild(document().createTextNode(valueCopy.impl()), IGNORE_EXCEPTION);
114    }
115}
116
117}
118