~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/webkit/WebCore/xml/XSLStyleSheetLibxslt.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This file is part of the XSL implementation.
 
3
 *
 
4
 * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Library General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This library is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
 * Library General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Library General Public License
 
17
 * along with this library; see the file COPYING.LIB.  If not, write to
 
18
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
19
 * Boston, MA 02110-1301, USA.
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
#include "XSLStyleSheet.h"
 
24
 
 
25
#if ENABLE(XSLT)
 
26
 
 
27
#include "CString.h"
 
28
#include "Console.h"
 
29
#include "DOMWindow.h"
 
30
#include "DocLoader.h"
 
31
#include "Document.h"
 
32
#include "Frame.h"
 
33
#include "Node.h"
 
34
#include "TransformSource.h"
 
35
#include "XMLTokenizer.h"
 
36
#include "XMLTokenizerScope.h"
 
37
#include "XSLImportRule.h"
 
38
#include "XSLTProcessor.h"
 
39
#include "loader.h"
 
40
 
 
41
#include <libxml/uri.h>
 
42
#include <libxslt/xsltutils.h>
 
43
 
 
44
#if PLATFORM(MAC)
 
45
#include "SoftLinking.h"
 
46
#endif
 
47
 
 
48
#if PLATFORM(MAC)
 
49
SOFT_LINK_LIBRARY(libxslt)
 
50
SOFT_LINK(libxslt, xsltIsBlank, int, (xmlChar *str), (str))
 
51
SOFT_LINK(libxslt, xsltGetNsProp, xmlChar *, (xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace), (node, name, nameSpace))
 
52
SOFT_LINK(libxslt, xsltParseStylesheetDoc, xsltStylesheetPtr, (xmlDocPtr doc), (doc))
 
53
SOFT_LINK(libxslt, xsltLoadStylesheetPI, xsltStylesheetPtr, (xmlDocPtr doc), (doc))
 
54
#endif
 
55
 
 
56
namespace WebCore {
 
57
 
 
58
XSLStyleSheet::XSLStyleSheet(XSLImportRule* parentRule, const String& href)
 
59
    : StyleSheet(parentRule, href)
 
60
    , m_ownerDocument(0)
 
61
    , m_embedded(false)
 
62
    , m_processed(false) // Child sheets get marked as processed when the libxslt engine has finally seen them.
 
63
    , m_stylesheetDoc(0)
 
64
    , m_stylesheetDocTaken(false)
 
65
    , m_parentStyleSheet(0)
 
66
{
 
67
}
 
68
 
 
69
XSLStyleSheet::XSLStyleSheet(Node* parentNode, const String& href,  bool embedded)
 
70
    : StyleSheet(parentNode, href)
 
71
    , m_ownerDocument(parentNode->document())
 
72
    , m_embedded(embedded)
 
73
    , m_processed(true) // The root sheet starts off processed.
 
74
    , m_stylesheetDoc(0)
 
75
    , m_stylesheetDocTaken(false)
 
76
    , m_parentStyleSheet(0)
 
77
{
 
78
}
 
79
 
 
80
XSLStyleSheet::~XSLStyleSheet()
 
81
{
 
82
    if (!m_stylesheetDocTaken)
 
83
        xmlFreeDoc(m_stylesheetDoc);
 
84
}
 
85
 
 
86
bool XSLStyleSheet::isLoading()
 
87
{
 
88
    unsigned len = length();
 
89
    for (unsigned i = 0; i < len; ++i) {
 
90
        StyleBase* rule = item(i);
 
91
        if (rule->isImportRule()) {
 
92
            XSLImportRule* import = static_cast<XSLImportRule*>(rule);
 
93
            if (import->isLoading())
 
94
                return true;
 
95
        }
 
96
    }
 
97
    return false;
 
98
}
 
99
 
 
100
void XSLStyleSheet::checkLoaded()
 
101
{
 
102
    if (isLoading())
 
103
        return;
 
104
    if (parent())
 
105
        parent()->checkLoaded();
 
106
    if (ownerNode())
 
107
        ownerNode()->sheetLoaded();
 
108
}
 
109
 
 
110
xmlDocPtr XSLStyleSheet::document()
 
111
{
 
112
    if (m_embedded && ownerDocument() && ownerDocument()->transformSource())
 
113
        return (xmlDocPtr)ownerDocument()->transformSource()->platformSource();
 
114
    return m_stylesheetDoc;
 
115
}
 
116
 
 
117
void XSLStyleSheet::clearDocuments()
 
118
{
 
119
    m_stylesheetDoc = 0;
 
120
    unsigned len = length();
 
121
    for (unsigned i = 0; i < len; ++i) {
 
122
        StyleBase* rule = item(i);
 
123
        if (rule->isImportRule()) {
 
124
            XSLImportRule* import = static_cast<XSLImportRule*>(rule);
 
125
            if (import->styleSheet())
 
126
                import->styleSheet()->clearDocuments();
 
127
        }
 
128
    }
 
129
}
 
130
 
 
131
DocLoader* XSLStyleSheet::docLoader()
 
132
{
 
133
    if (!m_ownerDocument)
 
134
        return 0;
 
135
    return m_ownerDocument->docLoader();
 
136
}
 
137
 
 
138
bool XSLStyleSheet::parseString(const String& string, bool)
 
139
{
 
140
    // Parse in a single chunk into an xmlDocPtr
 
141
    const UChar BOM = 0xFEFF;
 
142
    const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
 
143
    if (!m_stylesheetDocTaken)
 
144
        xmlFreeDoc(m_stylesheetDoc);
 
145
    m_stylesheetDocTaken = false;
 
146
 
 
147
    Console* console = 0;
 
148
    if (Frame* frame = ownerDocument()->frame())
 
149
        console = frame->domWindow()->console();
 
150
 
 
151
    XMLTokenizerScope scope(docLoader(), XSLTProcessor::genericErrorFunc, XSLTProcessor::parseErrorFunc, console);
 
152
 
 
153
    const char* buffer = reinterpret_cast<const char*>(string.characters());
 
154
    int size = string.length() * sizeof(UChar);
 
155
 
 
156
    xmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt(buffer, size);
 
157
 
 
158
    if (m_parentStyleSheet) {
 
159
        // The XSL transform may leave the newly-transformed document
 
160
        // with references to the symbol dictionaries of the style sheet
 
161
        // and any of its children. XML document disposal can corrupt memory
 
162
        // if a document uses more than one symbol dictionary, so we
 
163
        // ensure that all child stylesheets use the same dictionaries as their
 
164
        // parents.
 
165
        xmlDictFree(ctxt->dict);
 
166
        ctxt->dict = m_parentStyleSheet->m_stylesheetDoc->dict;
 
167
        xmlDictReference(ctxt->dict);
 
168
    }
 
169
 
 
170
    m_stylesheetDoc = xmlCtxtReadMemory(ctxt, buffer, size,
 
171
        href().utf8().data(),
 
172
        BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE",
 
173
        XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_NOWARNING | XML_PARSE_NOCDATA);
 
174
    xmlFreeParserCtxt(ctxt);
 
175
 
 
176
    loadChildSheets();
 
177
 
 
178
    return m_stylesheetDoc;
 
179
}
 
180
 
 
181
void XSLStyleSheet::loadChildSheets()
 
182
{
 
183
    if (!document())
 
184
        return;
 
185
 
 
186
    xmlNodePtr stylesheetRoot = document()->children;
 
187
 
 
188
    // Top level children may include other things such as DTD nodes, we ignore those.
 
189
    while (stylesheetRoot && stylesheetRoot->type != XML_ELEMENT_NODE)
 
190
        stylesheetRoot = stylesheetRoot->next;
 
191
 
 
192
    if (m_embedded) {
 
193
        // We have to locate (by ID) the appropriate embedded stylesheet element, so that we can walk the
 
194
        // import/include list.
 
195
        xmlAttrPtr idNode = xmlGetID(document(), (const xmlChar*)(href().utf8().data()));
 
196
        if (!idNode)
 
197
            return;
 
198
        stylesheetRoot = idNode->parent;
 
199
    } else {
 
200
        // FIXME: Need to handle an external URI with a # in it.  This is a pretty minor edge case, so we'll deal
 
201
        // with it later.
 
202
    }
 
203
 
 
204
    if (stylesheetRoot) {
 
205
        // Walk the children of the root element and look for import/include elements.
 
206
        // Imports must occur first.
 
207
        xmlNodePtr curr = stylesheetRoot->children;
 
208
        while (curr) {
 
209
            if (curr->type != XML_ELEMENT_NODE) {
 
210
                curr = curr->next;
 
211
                continue;
 
212
            }
 
213
            if (IS_XSLT_ELEM(curr) && IS_XSLT_NAME(curr, "import")) {
 
214
                xmlChar* uriRef = xsltGetNsProp(curr, (const xmlChar*)"href", XSLT_NAMESPACE);
 
215
                loadChildSheet(String::fromUTF8((const char*)uriRef));
 
216
                xmlFree(uriRef);
 
217
            } else
 
218
                break;
 
219
            curr = curr->next;
 
220
        }
 
221
 
 
222
        // Now handle includes.
 
223
        while (curr) {
 
224
            if (curr->type == XML_ELEMENT_NODE && IS_XSLT_ELEM(curr) && IS_XSLT_NAME(curr, "include")) {
 
225
                xmlChar* uriRef = xsltGetNsProp(curr, (const xmlChar*)"href", XSLT_NAMESPACE);
 
226
                loadChildSheet(String::fromUTF8((const char*)uriRef));
 
227
                xmlFree(uriRef);
 
228
            }
 
229
            curr = curr->next;
 
230
        }
 
231
    }
 
232
}
 
233
 
 
234
void XSLStyleSheet::loadChildSheet(const String& href)
 
235
{
 
236
    RefPtr<XSLImportRule> childRule = XSLImportRule::create(this, href);
 
237
    append(childRule);
 
238
    childRule->loadSheet();
 
239
}
 
240
 
 
241
xsltStylesheetPtr XSLStyleSheet::compileStyleSheet()
 
242
{
 
243
    // FIXME: Hook up error reporting for the stylesheet compilation process.
 
244
    if (m_embedded)
 
245
        return xsltLoadStylesheetPI(document());
 
246
 
 
247
    // xsltParseStylesheetDoc makes the document part of the stylesheet
 
248
    // so we have to release our pointer to it.
 
249
    ASSERT(!m_stylesheetDocTaken);
 
250
    xsltStylesheetPtr result = xsltParseStylesheetDoc(m_stylesheetDoc);
 
251
    if (result)
 
252
        m_stylesheetDocTaken = true;
 
253
    return result;
 
254
}
 
255
 
 
256
void XSLStyleSheet::setParentStyleSheet(XSLStyleSheet* parent)
 
257
{
 
258
    m_parentStyleSheet = parent;
 
259
    if (parent)
 
260
        m_ownerDocument = parent->ownerDocument();
 
261
}
 
262
 
 
263
xmlDocPtr XSLStyleSheet::locateStylesheetSubResource(xmlDocPtr parentDoc, const xmlChar* uri)
 
264
{
 
265
    bool matchedParent = (parentDoc == document());
 
266
    unsigned len = length();
 
267
    for (unsigned i = 0; i < len; ++i) {
 
268
        StyleBase* rule = item(i);
 
269
        if (rule->isImportRule()) {
 
270
            XSLImportRule* import = static_cast<XSLImportRule*>(rule);
 
271
            XSLStyleSheet* child = import->styleSheet();
 
272
            if (!child)
 
273
                continue;
 
274
            if (matchedParent) {
 
275
                if (child->processed())
 
276
                    continue; // libxslt has been given this sheet already.
 
277
 
 
278
                // Check the URI of the child stylesheet against the doc URI.
 
279
                // In order to ensure that libxml canonicalized both URLs, we get the original href
 
280
                // string from the import rule and canonicalize it using libxml before comparing it
 
281
                // with the URI argument.
 
282
                CString importHref = import->href().utf8();
 
283
                xmlChar* base = xmlNodeGetBase(parentDoc, (xmlNodePtr)parentDoc);
 
284
                xmlChar* childURI = xmlBuildURI((const xmlChar*)importHref.data(), base);
 
285
                bool equalURIs = xmlStrEqual(uri, childURI);
 
286
                xmlFree(base);
 
287
                xmlFree(childURI);
 
288
                if (equalURIs) {
 
289
                    child->markAsProcessed();
 
290
                    return child->document();
 
291
                }
 
292
            } else {
 
293
                xmlDocPtr result = import->styleSheet()->locateStylesheetSubResource(parentDoc, uri);
 
294
                if (result)
 
295
                    return result;
 
296
            }
 
297
        }
 
298
    }
 
299
 
 
300
    return 0;
 
301
}
 
302
 
 
303
void XSLStyleSheet::markAsProcessed()
 
304
{
 
305
    ASSERT(!m_processed);
 
306
    ASSERT(!m_stylesheetDocTaken);
 
307
    m_processed = true;
 
308
    m_stylesheetDocTaken = true;
 
309
}
 
310
 
 
311
} // namespace WebCore
 
312
 
 
313
#endif // ENABLE(XSLT)