summaryrefslogtreecommitdiffstats
path: root/webkit/pending
diff options
context:
space:
mode:
authorsgk@google.com <sgk@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-14 12:50:31 +0000
committersgk@google.com <sgk@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-14 12:50:31 +0000
commitf6c135caf66962d03f769d1255c62496f0c147c0 (patch)
treedc7aee39e98e7513bb2499f28a28ab56ee467b65 /webkit/pending
parent28964759b5c023b457ca6c8bd96a7e10e5bc5852 (diff)
downloadchromium_src-f6c135caf66962d03f769d1255c62496f0c147c0.zip
chromium_src-f6c135caf66962d03f769d1255c62496f0c147c0.tar.gz
chromium_src-f6c135caf66962d03f769d1255c62496f0c147c0.tar.bz2
Remove no-longer-referenced webkit\pending files.
Review URL: http://codereview.chromium.org/7132 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3342 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/pending')
-rw-r--r--webkit/pending/GIFImageDecoder.cpp417
-rw-r--r--webkit/pending/KURL.cpp1606
-rw-r--r--webkit/pending/KURL.h447
-rw-r--r--webkit/pending/NodeFilter.cpp45
-rw-r--r--webkit/pending/NodeFilter.h89
-rw-r--r--webkit/pending/NodeFilterCondition.cpp39
-rw-r--r--webkit/pending/NodeFilterCondition.h44
-rw-r--r--webkit/pending/NodeIterator.cpp239
-rw-r--r--webkit/pending/NodeIterator.h83
-rw-r--r--webkit/pending/Page.cpp577
-rw-r--r--webkit/pending/Page.h239
-rw-r--r--webkit/pending/RenderButton.cpp152
-rw-r--r--webkit/pending/RenderButton.h75
-rw-r--r--webkit/pending/RenderPartObject.cpp342
-rw-r--r--webkit/pending/RenderText.cpp1176
-rw-r--r--webkit/pending/RenderTextControl.cpp1306
-rw-r--r--webkit/pending/Selection.cpp607
-rw-r--r--webkit/pending/Settings.cpp393
-rw-r--r--webkit/pending/Settings.h237
-rw-r--r--webkit/pending/SimpleFontData.cpp255
-rw-r--r--webkit/pending/SimpleFontData.h228
-rw-r--r--webkit/pending/TextCodecICU.cpp457
-rw-r--r--webkit/pending/TextResourceDecoder.cpp894
-rw-r--r--webkit/pending/TextResourceDecoder.h86
-rw-r--r--webkit/pending/TreeWalker.cpp319
-rw-r--r--webkit/pending/TreeWalker.h75
-rw-r--r--webkit/pending/XMLHttpRequest.cpp1381
-rw-r--r--webkit/pending/XMLHttpRequest.h250
-rw-r--r--webkit/pending/XSLImportRule.cpp117
-rw-r--r--webkit/pending/XSLStyleSheet.cpp316
-rw-r--r--webkit/pending/XSLStyleSheet.h104
-rw-r--r--webkit/pending/pcre_exec.cpp2176
32 files changed, 0 insertions, 14771 deletions
diff --git a/webkit/pending/GIFImageDecoder.cpp b/webkit/pending/GIFImageDecoder.cpp
deleted file mode 100644
index d350d2c..0000000
--- a/webkit/pending/GIFImageDecoder.cpp
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "GIFImageDecoder.h"
-#include "GIFImageReader.h"
-
-#if PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX)
-
-namespace WebCore {
-
-class GIFImageDecoderPrivate
-{
-public:
- GIFImageDecoderPrivate(GIFImageDecoder* decoder = 0)
- : m_reader(decoder)
- {
- m_readOffset = 0;
- }
-
- ~GIFImageDecoderPrivate()
- {
- m_reader.close();
- }
-
- bool decode(SharedBuffer* data,
- GIFImageDecoder::GIFQuery query = GIFImageDecoder::GIFFullQuery,
- unsigned int haltFrame = -1)
- {
- return m_reader.read((const unsigned char*)data->data() + m_readOffset, data->size() - m_readOffset,
- query,
- haltFrame);
- }
-
- unsigned frameCount() const { return m_reader.images_count; }
- int repetitionCount() const { return m_reader.loop_count; }
-
- void setReadOffset(unsigned o) { m_readOffset = o; }
-
- bool isTransparent() const { return m_reader.frame_reader->is_transparent; }
-
- void getColorMap(unsigned char*& map, unsigned& size) const {
- if (m_reader.frame_reader->is_local_colormap_defined) {
- map = m_reader.frame_reader->local_colormap;
- size = (unsigned)m_reader.frame_reader->local_colormap_size;
- } else {
- map = m_reader.global_colormap;
- size = m_reader.global_colormap_size;
- }
- }
-
- unsigned frameXOffset() const { return m_reader.frame_reader->x_offset; }
- unsigned frameYOffset() const { return m_reader.frame_reader->y_offset; }
- unsigned frameWidth() const { return m_reader.frame_reader->width; }
- unsigned frameHeight() const { return m_reader.frame_reader->height; }
-
- int transparentPixel() const { return m_reader.frame_reader->tpixel; }
-
- unsigned duration() const { return m_reader.frame_reader->delay_time; }
-
-private:
- GIFImageReader m_reader;
- unsigned m_readOffset;
-};
-
-GIFImageDecoder::GIFImageDecoder()
-: m_frameCountValid(true), m_repetitionCount(cAnimationLoopOnce), m_reader(0)
-{}
-
-GIFImageDecoder::~GIFImageDecoder()
-{
- delete m_reader;
-}
-
-// Take the data and store it.
-void GIFImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
-{
- if (m_failed)
- return;
-
- // Cache our new data.
- ImageDecoder::setData(data, allDataReceived);
-
- // Our frame count is now unknown.
- m_frameCountValid = false;
-
- // Create the GIF reader.
- if (!m_reader && !m_failed)
- m_reader = new GIFImageDecoderPrivate(this);
-}
-
-// Whether or not the size information has been decoded yet.
-bool GIFImageDecoder::isSizeAvailable() const
-{
- // If we have pending data to decode, send it to the GIF reader now.
- if (!m_sizeAvailable && m_reader) {
- if (m_failed)
- return false;
-
- // The decoder will go ahead and aggressively consume everything up until the first
- // size is encountered.
- decode(GIFSizeQuery, 0);
- }
-
- return m_sizeAvailable;
-}
-
-// The total number of frames for the image. Will scan the image data for the answer
-// (without necessarily decoding all of the individual frames).
-int GIFImageDecoder::frameCount()
-{
- // If the decoder had an earlier error, we will just return what we had decoded
- // so far.
- if (!m_frameCountValid) {
- // FIXME: Scanning all the data has O(n^2) behavior if the data were to come in really
- // slowly. Might be interesting to try to clone our existing read session to preserve
- // state, but for now we just crawl all the data. Note that this is no worse than what
- // ImageIO does on Mac right now (it also crawls all the data again).
- GIFImageDecoderPrivate reader;
- reader.decode(m_data.get(), GIFFrameCountQuery);
- m_frameCountValid = true;
- m_frameBufferCache.resize(reader.frameCount());
- }
-
- return m_frameBufferCache.size();
-}
-
-// The number of repetitions to perform for an animation loop.
-int GIFImageDecoder::repetitionCount() const
-{
- // This value can arrive at any point in the image data stream. Most GIFs
- // in the wild declare it near the beginning of the file, so it usually is
- // set by the time we've decoded the size, but (depending on the GIF and the
- // packets sent back by the webserver) not always. Our caller is
- // responsible for waiting until image decoding has finished to ask this if
- // it needs an authoritative answer. In the meantime, we should default to
- // "loop once", both in the reader and here.
- if (m_reader)
- m_repetitionCount = m_reader->repetitionCount();
- return m_repetitionCount;
-}
-
-RGBA32Buffer* GIFImageDecoder::frameBufferAtIndex(size_t index)
-{
- if (index >= frameCount())
- return 0;
-
- RGBA32Buffer& frame = m_frameBufferCache[index];
- if (frame.status() != RGBA32Buffer::FrameComplete && m_reader)
- // Decode this frame.
- decode(GIFFullQuery, index+1);
- return &frame;
-}
-
-// Feed data to the GIF reader.
-void GIFImageDecoder::decode(GIFQuery query, unsigned haltAtFrame) const
-{
- if (m_failed)
- return;
-
- m_failed = !m_reader->decode(m_data.get(), query, haltAtFrame);
-
- if (m_failed) {
- delete m_reader;
- m_reader = 0;
- }
-}
-
-// Callbacks from the GIF reader.
-void GIFImageDecoder::sizeNowAvailable(unsigned width, unsigned height)
-{
- m_size = IntSize(width, height);
- m_sizeAvailable = true;
-}
-
-void GIFImageDecoder::decodingHalted(unsigned bytesLeft)
-{
- m_reader->setReadOffset(m_data->size() - bytesLeft);
-}
-
-void GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
-{
- // Initialize the frame rect in our buffer.
- IntRect frameRect(m_reader->frameXOffset(), m_reader->frameYOffset(),
- m_reader->frameWidth(), m_reader->frameHeight());
-
- // Make sure the frameRect doesn't extend past the bottom-right of the buffer.
- if (frameRect.right() > m_size.width())
- frameRect.setWidth(m_size.width() - m_reader->frameXOffset());
- if (frameRect.bottom() > m_size.height())
- frameRect.setHeight(m_size.height() - m_reader->frameYOffset());
-
- RGBA32Buffer* const buffer = &m_frameBufferCache[frameIndex];
- buffer->setRect(frameRect);
-
- if (frameIndex == 0) {
- // This is the first frame, so we're not relying on any previous data.
- prepEmptyFrameBuffer(buffer);
- } else {
- // The starting state for this frame depends on the previous frame's
- // disposal method.
- //
- // Frames that use the DisposeOverwritePrevious method are effectively
- // no-ops in terms of changing the starting state of a frame compared to
- // the starting state of the previous frame, so skip over them. (If the
- // first frame specifies this method, it will get treated like
- // DisposeOverwriteBgcolor below and reset to a completely empty image.)
- const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex];
- RGBA32Buffer::FrameDisposalMethod prevMethod =
- prevBuffer->disposalMethod();
- while ((frameIndex > 0) &&
- (prevMethod == RGBA32Buffer::DisposeOverwritePrevious)) {
- prevBuffer = &m_frameBufferCache[--frameIndex];
- prevMethod = prevBuffer->disposalMethod();
- }
-
- if ((prevMethod == RGBA32Buffer::DisposeNotSpecified) ||
- (prevMethod == RGBA32Buffer::DisposeKeep)) {
- // Preserve the last frame as the starting state for this frame.
- buffer->copyBitmapData(*prevBuffer);
- // This next line isn't currently necessary since the alpha state is
- // currently carried along in the Skia bitmap data, but it's safe,
- // future-proof, and parallel to the Cairo code.
- buffer->setHasAlpha(prevBuffer->hasAlpha());
- } else {
- // We want to clear the previous frame to transparent, without
- // affecting pixels in the image outside of the frame.
- const IntRect& prevRect = prevBuffer->rect();
- if ((frameIndex == 0) ||
- prevRect.contains(IntRect(IntPoint(0, 0), m_size))) {
- // Clearing the first frame, or a frame the size of the whole
- // image, results in a completely empty image.
- prepEmptyFrameBuffer(buffer);
- } else {
- // Copy the whole previous buffer, then clear just its frame.
- buffer->copyBitmapData(*prevBuffer);
- // Unnecessary (but safe); see comments on the similar call above.
- buffer->setHasAlpha(prevBuffer->hasAlpha());
- SkBitmap& bitmap = buffer->bitmap();
- for (int y = prevRect.y(); y < prevRect.bottom(); ++y) {
- for (int x = prevRect.x(); x < prevRect.right(); ++x)
- buffer->setRGBA(bitmap.getAddr32(x, y), 0, 0, 0, 0);
- }
- if ((prevRect.width() > 0) && (prevRect.height() > 0))
- buffer->setHasAlpha(true);
- }
- }
- }
-
- // Update our status to be partially complete.
- buffer->setStatus(RGBA32Buffer::FramePartial);
-
- // Reset the alpha pixel tracker for this frame.
- m_currentBufferSawAlpha = false;
-}
-
-void GIFImageDecoder::prepEmptyFrameBuffer(RGBA32Buffer* buffer) const
-{
- buffer->setSize(m_size.width(), m_size.height());
- buffer->bitmap().eraseARGB(0, 0, 0, 0);
- // This next line isn't currently necessary since Skia's eraseARGB() sets
- // this for us, but we do it for similar reasons to the setHasAlpha() calls
- // in initFrameBuffer() above.
- buffer->setHasAlpha(true);
-}
-
-void GIFImageDecoder::haveDecodedRow(unsigned frameIndex,
- unsigned char* rowBuffer, // Pointer to single scanline temporary buffer
- unsigned char* rowEnd,
- unsigned rowNumber, // The row index
- unsigned repeatCount, // How many times to repeat the row
- bool writeTransparentPixels)
-{
- // Initialize the frame if necessary.
- RGBA32Buffer& buffer = m_frameBufferCache[frameIndex];
- if (buffer.status() == RGBA32Buffer::FrameEmpty)
- initFrameBuffer(frameIndex);
-
- // Do nothing for bogus data.
- if (rowBuffer == 0 || static_cast<int>(m_reader->frameYOffset() + rowNumber) >= m_size.height())
- return;
-
- unsigned colorMapSize;
- unsigned char* colorMap;
- m_reader->getColorMap(colorMap, colorMapSize);
- if (!colorMap)
- return;
-
- // The buffers that we draw are the entire image's width and height, so a final output frame is
- // width * height RGBA32 values in size.
- //
- // A single GIF frame, however, can be smaller than the entire image, i.e., it can represent some sub-rectangle
- // within the overall image. The rows we are decoding are within this
- // sub-rectangle. This means that if the GIF frame's sub-rectangle is (x,y,w,h) then row 0 is really row
- // y, and each row goes from x to x+w.
- unsigned dstPos = (m_reader->frameYOffset() + rowNumber) * m_size.width() + m_reader->frameXOffset();
- unsigned* dst = buffer.bitmap().getAddr32(0, 0) + dstPos;
- unsigned* dstEnd = dst + m_size.width() - m_reader->frameXOffset();
- unsigned* currDst = dst;
- unsigned char* currentRowByte = rowBuffer;
-
- while (currentRowByte != rowEnd && currDst < dstEnd) {
- if ((!m_reader->isTransparent() || *currentRowByte != m_reader->transparentPixel()) && *currentRowByte < colorMapSize) {
- unsigned colorIndex = *currentRowByte * 3;
- unsigned red = colorMap[colorIndex];
- unsigned green = colorMap[colorIndex + 1];
- unsigned blue = colorMap[colorIndex + 2];
- RGBA32Buffer::setRGBA(currDst, red, green, blue, 255);
- } else {
- m_currentBufferSawAlpha = true;
- // We may or may not need to write transparent pixels to the buffer.
- // If we're compositing against a previous image, it's wrong, and if
- // we're writing atop a cleared, fully transparent buffer, it's
- // unnecessary; but if we're decoding an interlaced gif and
- // displaying it "Haeberli"-style, we must write these for passes
- // beyond the first, or the initial passes will "show through" the
- // later ones.
- if (writeTransparentPixels)
- RGBA32Buffer::setRGBA(currDst, 0, 0, 0, 0);
- }
- currDst++;
- currentRowByte++;
- }
-
- if (repeatCount > 1) {
- // Copy the row |repeatCount|-1 times.
- unsigned num = currDst - dst;
- unsigned size = num * sizeof(unsigned);
- unsigned width = m_size.width();
- unsigned* end = buffer.bitmap().getAddr32(0, 0) + width * m_size.height();
- currDst = dst + width;
- for (unsigned i = 1; i < repeatCount; i++) {
- if (currDst + num > end) // Protect against a buffer overrun from a bogus repeatCount.
- break;
- memcpy(currDst, dst, size);
- currDst += width;
- }
- }
-}
-
-void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, RGBA32Buffer::FrameDisposalMethod disposalMethod)
-{
- RGBA32Buffer& buffer = m_frameBufferCache[frameIndex];
- buffer.setStatus(RGBA32Buffer::FrameComplete);
- buffer.setDuration(frameDuration);
- buffer.setDisposalMethod(disposalMethod);
-
- if (!m_currentBufferSawAlpha) {
- // The whole frame was non-transparent, so it's possible that the entire
- // resulting buffer was non-transparent, and we can setHasAlpha(false).
- if (buffer.rect().contains(IntRect(IntPoint(0, 0), m_size))) {
- buffer.setHasAlpha(false);
- } else if (frameIndex > 0) {
- // Tricky case. This frame does not have alpha only if everywhere
- // outside its rect doesn't have alpha. To know whether this is
- // true, we check the start state of the frame -- if it doesn't have
- // alpha, we're safe.
- //
- // First skip over prior DisposeOverwritePrevious frames (since they
- // don't affect the start state of this frame) the same way we do in
- // initFrameBuffer().
- const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex];
- while ((frameIndex > 0) &&
- (prevBuffer->disposalMethod() ==
- RGBA32Buffer::DisposeOverwritePrevious))
- prevBuffer = &m_frameBufferCache[--frameIndex];
-
- // Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then
- // we can say we have no alpha if that frame had no alpha. But
- // since in initFrameBuffer() we already copied that frame's alpha
- // state into the current frame's, we need do nothing at all here.
- //
- // The only remaining case is a DisposeOverwriteBgcolor frame. If
- // it had no alpha, and its rect is contained in the current frame's
- // rect, we know the current frame has no alpha.
- if ((prevBuffer->disposalMethod() ==
- RGBA32Buffer::DisposeOverwriteBgcolor) &&
- !prevBuffer->hasAlpha() &&
- buffer.rect().contains(prevBuffer->rect()))
- buffer.setHasAlpha(false);
- }
- }
-}
-
-void GIFImageDecoder::gifComplete()
-{
- if (m_reader)
- m_repetitionCount = m_reader->repetitionCount();
- delete m_reader;
- m_reader = 0;
-}
-
-}
-
-#endif // PLATFORM(CAIRO)
diff --git a/webkit/pending/KURL.cpp b/webkit/pending/KURL.cpp
deleted file mode 100644
index 00166ff..0000000
--- a/webkit/pending/KURL.cpp
+++ /dev/null
@@ -1,1606 +0,0 @@
-/*
- * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "KURL.h"
-
-#ifndef USE_GOOGLE_URL_LIBRARY
-
-#include "CString.h"
-#include "PlatformString.h"
-#include "TextEncoding.h"
-
-#if USE(ICU_UNICODE)
-#include <unicode/uidna.h>
-#elif USE(QT4_UNICODE)
-#include <QUrl>
-#endif
-
-#include <stdio.h>
-
-using namespace std;
-using namespace WTF;
-
-namespace WebCore {
-
-typedef Vector<char, 512> CharBuffer;
-typedef Vector<UChar, 512> UCharBuffer;
-
-// FIXME: This file makes too much use of the + operator on String.
-// We either have to optimize that operator so it doesn't involve
-// so many allocations, or change this to use Vector<UChar> instead.
-
-enum URLCharacterClasses {
- // alpha
- SchemeFirstChar = 1 << 0,
-
- // ( alpha | digit | "+" | "-" | "." )
- SchemeChar = 1 << 1,
-
- // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
- // unreserved = alphanum | mark
- // ( unreserved | escaped | ";" | ":" | "&" | "=" | "+" | "$" | "," )
- UserInfoChar = 1 << 2,
-
- // alnum | "." | "-" | "%"
- // The above is what the specification says, but we are lenient to
- // match existing practice and also allow:
- // "_"
- HostnameChar = 1 << 3,
-
- // hexdigit | ":" | "%"
- IPv6Char = 1 << 4,
-
- // "#" | "?" | "/" | nul
- PathSegmentEndChar = 1 << 5,
-
- // not allowed in path
- BadChar = 1 << 6
-};
-
-static const char hexDigits[17] = "0123456789ABCDEF";
-
-static const unsigned char characterClassTable[256] = {
- /* 0 nul */ PathSegmentEndChar, /* 1 soh */ BadChar,
- /* 2 stx */ BadChar, /* 3 etx */ BadChar,
- /* 4 eot */ BadChar, /* 5 enq */ BadChar, /* 6 ack */ BadChar, /* 7 bel */ BadChar,
- /* 8 bs */ BadChar, /* 9 ht */ BadChar, /* 10 nl */ BadChar, /* 11 vt */ BadChar,
- /* 12 np */ BadChar, /* 13 cr */ BadChar, /* 14 so */ BadChar, /* 15 si */ BadChar,
- /* 16 dle */ BadChar, /* 17 dc1 */ BadChar, /* 18 dc2 */ BadChar, /* 19 dc3 */ BadChar,
- /* 20 dc4 */ BadChar, /* 21 nak */ BadChar, /* 22 syn */ BadChar, /* 23 etb */ BadChar,
- /* 24 can */ BadChar, /* 25 em */ BadChar, /* 26 sub */ BadChar, /* 27 esc */ BadChar,
- /* 28 fs */ BadChar, /* 29 gs */ BadChar, /* 30 rs */ BadChar, /* 31 us */ BadChar,
- /* 32 sp */ BadChar, /* 33 ! */ UserInfoChar,
- /* 34 " */ BadChar, /* 35 # */ PathSegmentEndChar | BadChar,
- /* 36 $ */ UserInfoChar, /* 37 % */ UserInfoChar | HostnameChar | IPv6Char | BadChar,
- /* 38 & */ UserInfoChar, /* 39 ' */ UserInfoChar,
- /* 40 ( */ UserInfoChar, /* 41 ) */ UserInfoChar,
- /* 42 * */ UserInfoChar, /* 43 + */ SchemeChar | UserInfoChar,
- /* 44 , */ UserInfoChar,
- /* 45 - */ SchemeChar | UserInfoChar | HostnameChar,
- /* 46 . */ SchemeChar | UserInfoChar | HostnameChar,
- /* 47 / */ PathSegmentEndChar,
- /* 48 0 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 49 1 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 50 2 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 51 3 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 52 4 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 53 5 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 54 6 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 55 7 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 56 8 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 57 9 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 58 : */ UserInfoChar | IPv6Char, /* 59 ; */ UserInfoChar,
- /* 60 < */ BadChar, /* 61 = */ UserInfoChar,
- /* 62 > */ BadChar, /* 63 ? */ PathSegmentEndChar | BadChar,
- /* 64 @ */ 0,
- /* 65 A */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 66 B */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 67 C */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 68 D */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 69 E */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 70 F */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 71 G */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 72 H */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 73 I */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 74 J */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 75 K */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 76 L */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 77 M */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 78 N */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 79 O */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 80 P */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 81 Q */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 82 R */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 83 S */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 84 T */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 85 U */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 86 V */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 87 W */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 88 X */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 89 Y */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 90 Z */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 91 [ */ 0,
- /* 92 \ */ 0, /* 93 ] */ 0,
- /* 94 ^ */ 0,
- /* 95 _ */ UserInfoChar | HostnameChar,
- /* 96 ` */ 0,
- /* 97 a */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 98 b */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 99 c */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 100 d */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 101 e */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 102 f */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 103 g */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 104 h */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 105 i */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 106 j */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 107 k */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 108 l */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 109 m */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 110 n */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 111 o */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 112 p */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 113 q */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 114 r */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 115 s */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 116 t */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 117 u */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 118 v */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 119 w */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 120 x */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 121 y */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 122 z */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
- /* 123 { */ 0,
- /* 124 | */ 0, /* 125 } */ 0, /* 126 ~ */ UserInfoChar, /* 127 del */ BadChar,
- /* 128 */ BadChar, /* 129 */ BadChar, /* 130 */ BadChar, /* 131 */ BadChar,
- /* 132 */ BadChar, /* 133 */ BadChar, /* 134 */ BadChar, /* 135 */ BadChar,
- /* 136 */ BadChar, /* 137 */ BadChar, /* 138 */ BadChar, /* 139 */ BadChar,
- /* 140 */ BadChar, /* 141 */ BadChar, /* 142 */ BadChar, /* 143 */ BadChar,
- /* 144 */ BadChar, /* 145 */ BadChar, /* 146 */ BadChar, /* 147 */ BadChar,
- /* 148 */ BadChar, /* 149 */ BadChar, /* 150 */ BadChar, /* 151 */ BadChar,
- /* 152 */ BadChar, /* 153 */ BadChar, /* 154 */ BadChar, /* 155 */ BadChar,
- /* 156 */ BadChar, /* 157 */ BadChar, /* 158 */ BadChar, /* 159 */ BadChar,
- /* 160 */ BadChar, /* 161 */ BadChar, /* 162 */ BadChar, /* 163 */ BadChar,
- /* 164 */ BadChar, /* 165 */ BadChar, /* 166 */ BadChar, /* 167 */ BadChar,
- /* 168 */ BadChar, /* 169 */ BadChar, /* 170 */ BadChar, /* 171 */ BadChar,
- /* 172 */ BadChar, /* 173 */ BadChar, /* 174 */ BadChar, /* 175 */ BadChar,
- /* 176 */ BadChar, /* 177 */ BadChar, /* 178 */ BadChar, /* 179 */ BadChar,
- /* 180 */ BadChar, /* 181 */ BadChar, /* 182 */ BadChar, /* 183 */ BadChar,
- /* 184 */ BadChar, /* 185 */ BadChar, /* 186 */ BadChar, /* 187 */ BadChar,
- /* 188 */ BadChar, /* 189 */ BadChar, /* 190 */ BadChar, /* 191 */ BadChar,
- /* 192 */ BadChar, /* 193 */ BadChar, /* 194 */ BadChar, /* 195 */ BadChar,
- /* 196 */ BadChar, /* 197 */ BadChar, /* 198 */ BadChar, /* 199 */ BadChar,
- /* 200 */ BadChar, /* 201 */ BadChar, /* 202 */ BadChar, /* 203 */ BadChar,
- /* 204 */ BadChar, /* 205 */ BadChar, /* 206 */ BadChar, /* 207 */ BadChar,
- /* 208 */ BadChar, /* 209 */ BadChar, /* 210 */ BadChar, /* 211 */ BadChar,
- /* 212 */ BadChar, /* 213 */ BadChar, /* 214 */ BadChar, /* 215 */ BadChar,
- /* 216 */ BadChar, /* 217 */ BadChar, /* 218 */ BadChar, /* 219 */ BadChar,
- /* 220 */ BadChar, /* 221 */ BadChar, /* 222 */ BadChar, /* 223 */ BadChar,
- /* 224 */ BadChar, /* 225 */ BadChar, /* 226 */ BadChar, /* 227 */ BadChar,
- /* 228 */ BadChar, /* 229 */ BadChar, /* 230 */ BadChar, /* 231 */ BadChar,
- /* 232 */ BadChar, /* 233 */ BadChar, /* 234 */ BadChar, /* 235 */ BadChar,
- /* 236 */ BadChar, /* 237 */ BadChar, /* 238 */ BadChar, /* 239 */ BadChar,
- /* 240 */ BadChar, /* 241 */ BadChar, /* 242 */ BadChar, /* 243 */ BadChar,
- /* 244 */ BadChar, /* 245 */ BadChar, /* 246 */ BadChar, /* 247 */ BadChar,
- /* 248 */ BadChar, /* 249 */ BadChar, /* 250 */ BadChar, /* 251 */ BadChar,
- /* 252 */ BadChar, /* 253 */ BadChar, /* 254 */ BadChar, /* 255 */ BadChar
-};
-
-static int copyPathRemovingDots(char* dst, const char* src, int srcStart, int srcEnd);
-static void encodeRelativeString(const String& rel, const TextEncoding&, CharBuffer& ouput);
-static String substituteBackslashes(const String&);
-
-static inline bool isSchemeFirstChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & SchemeFirstChar; }
-static inline bool isSchemeFirstChar(UChar c) { return c <= 0xff && (characterClassTable[c] & SchemeFirstChar); }
-static inline bool isSchemeChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & SchemeChar; }
-static inline bool isSchemeChar(UChar c) { return c <= 0xff && (characterClassTable[c] & SchemeChar); }
-static inline bool isUserInfoChar(unsigned char c) { return characterClassTable[c] & UserInfoChar; }
-static inline bool isHostnameChar(unsigned char c) { return characterClassTable[c] & HostnameChar; }
-static inline bool isIPv6Char(unsigned char c) { return characterClassTable[c] & IPv6Char; }
-static inline bool isPathSegmentEndChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & PathSegmentEndChar; }
-static inline bool isPathSegmentEndChar(UChar c) { return c <= 0xff && (characterClassTable[c] & PathSegmentEndChar); }
-static inline bool isBadChar(unsigned char c) { return characterClassTable[c] & BadChar; }
-
-static inline int hexDigitValue(UChar c)
-{
- ASSERT(isASCIIHexDigit(c));
- if (c < 'A')
- return c - '0';
- return (c - 'A' + 10) & 0xF; // handle both upper and lower case without a branch
-}
-
-// Copies the source to the destination, assuming all the source characters are
-// ASCII. The destination buffer must be large enough. Null characters are allowed
-// in the source string, and no attempt is made to null-terminate the result.
-static void copyASCII(const UChar* src, int length, char* dest)
-{
- for (int i = 0; i < length; i++)
- dest[i] = static_cast<char>(src[i]);
-}
-
-// FIXME: Move to PlatformString.h eventually.
-// Returns the index of the first index in string |s| of any of the characters
-// in |toFind|. |toFind| should be a null-terminated string, all characters up
-// to the null will be searched. Returns int if not found.
-static int findFirstOf(const UChar* s, int sLen, int startPos, const char* toFind)
-{
- for (int i = startPos; i < sLen; i++) {
- const char* cur = toFind;
- while (*cur) {
- if (s[i] == *(cur++))
- return i;
- }
- }
- return -1;
-}
-
-#ifndef KURL_DECORATE_GLOBALS
-inline bool KURL::protocolIs(const String& string, const char* protocol)
-{
- return WebCore::protocolIs(string, protocol);
-}
-#endif
-
-void KURL::invalidate()
-{
- m_isValid = false;
- m_schemeEnd = 0;
- m_userStart = 0;
- m_userEnd = 0;
- m_passwordEnd = 0;
- m_hostEnd = 0;
- m_portEnd = 0;
- m_pathEnd = 0;
- m_pathAfterLastSlash = 0;
- m_queryEnd = 0;
- m_fragmentEnd = 0;
-}
-
-KURL::KURL(const char* url)
-{
- if (!url || url[0] != '/') {
- parse(url, 0);
- return;
- }
-
- size_t urlLength = strlen(url) + 1;
- CharBuffer buffer(urlLength + 5); // 5 for "file:".
- buffer[0] = 'f';
- buffer[1] = 'i';
- buffer[2] = 'l';
- buffer[3] = 'e';
- buffer[4] = ':';
- memcpy(&buffer[5], url, urlLength);
- parse(buffer.data(), 0);
-}
-
-KURL::KURL(const String& url)
-{
- if (url[0] != '/') {
- parse(url);
- return;
- }
-
- CharBuffer buffer(url.length() + 6); // 5 for "file:", 1 for terminator.
- buffer[0] = 'f';
- buffer[1] = 'i';
- buffer[2] = 'l';
- buffer[3] = 'e';
- buffer[4] = ':';
- copyASCII(url.characters(), url.length(), &buffer[5]);
- buffer[url.length() + 5] = '\0'; // Need null terminator.
-
- parse(buffer.data(), 0);
-}
-
-KURL::KURL(const KURL& base, const String& relative)
-{
- init(base, relative, UTF8Encoding());
-}
-
-KURL::KURL(const KURL& base, const String& relative, const TextEncoding& encoding)
-{
- init(base, relative, encoding);
-}
-
-void KURL::init(const KURL& base, const String& relative, const TextEncoding& encoding)
-{
- // Allow resolutions with a null or empty base URL, but not with any other invalid one.
- // FIXME: Is this a good rule?
- if (!base.m_isValid && !base.isEmpty()) {
- m_string = relative;
- invalidate();
- return;
- }
-
- // For compatibility with Win IE, treat backslashes as if they were slashes,
- // as long as we're not dealing with javascript: or data: URLs.
- String rel = relative;
- if (rel.contains('\\') && !(protocolIs(rel, "javascript") || protocolIs(rel, "data")))
- rel = substituteBackslashes(rel);
-
- String* originalString = &rel;
-
- bool allASCII = charactersAreAllASCII(rel.characters(), rel.length());
- CharBuffer strBuffer;
- char* str;
- size_t len;
- if (allASCII) {
- len = rel.length();
- strBuffer.resize(len + 1);
- copyASCII(rel.characters(), len, strBuffer.data());
- strBuffer[len] = 0;
- str = strBuffer.data();
- } else {
- originalString = 0;
- encodeRelativeString(rel, encoding, strBuffer);
- str = strBuffer.data();
- len = strlen(str);
- }
-
- // Get rid of leading whitespace.
- while (*str == ' ') {
- originalString = 0;
- str++;
- --len;
- }
-
- // Get rid of trailing whitespace.
- while (len && str[len - 1] == ' ') {
- originalString = 0;
- str[--len] = '\0';
- }
-
- // According to the RFC, the reference should be interpreted as an
- // absolute URI if possible, using the "leftmost, longest"
- // algorithm. If the URI reference is absolute it will have a
- // scheme, meaning that it will have a colon before the first
- // non-scheme element.
- bool absolute = false;
- char* p = str;
- if (isSchemeFirstChar(*p)) {
- ++p;
- while (isSchemeChar(*p)) {
- ++p;
- }
- if (*p == ':') {
- if (p[1] != '/' && equalIgnoringCase(base.protocol(), String(str, p - str)) && base.isHierarchical()) {
- str = p + 1;
- originalString = 0;
- } else
- absolute = true;
- }
- }
-
- if (absolute) {
- parse(str, originalString);
- } else {
- // If the base is empty or opaque (e.g. data: or javascript:), then the URL is invalid
- // unless the relative URL is a single fragment.
- if (!base.isHierarchical()) {
- if (str[0] == '#')
- parse(base.m_string.left(base.m_queryEnd) + (allASCII ? String(str) : String::fromUTF8(str)));
- else {
- m_string = relative;
- invalidate();
- }
- return;
- }
-
- switch (str[0]) {
- case '\0':
- // the reference must be empty - the RFC says this is a
- // reference to the same document
- *this = base;
- break;
- case '#':
- // must be fragment-only reference
- parse(base.m_string.left(base.m_queryEnd) + (allASCII ? String(str) : String::fromUTF8(str)));
- break;
- case '?':
- // query-only reference, special case needed for non-URL results
- parse(base.m_string.left(base.m_pathEnd) + (allASCII ? String(str) : String::fromUTF8(str)));
- break;
- case '/':
- // must be net-path or absolute-path reference
- if (str[1] == '/') {
- // net-path
- parse(base.m_string.left(base.m_schemeEnd + 1) + (allASCII ? String(str) : String::fromUTF8(str)));
- } else {
- // abs-path
- parse(base.m_string.left(base.m_portEnd) + (allASCII ? String(str) : String::fromUTF8(str)));
- }
- break;
- default:
- {
- // must be relative-path reference
-
- // Base part plus relative part plus one possible slash added in between plus terminating \0 byte.
- CharBuffer buffer(base.m_pathEnd + 1 + len + 1);
-
- char* bufferPos = buffer.data();
-
- // first copy everything before the path from the base
- unsigned baseLength = base.m_string.length();
- const UChar* baseCharacters = base.m_string.characters();
- CharBuffer baseStringBuffer(baseLength);
- for (unsigned i = 0; i < baseLength; ++i)
- baseStringBuffer[i] = static_cast<char>(baseCharacters[i]);
- const char* baseString = baseStringBuffer.data();
- const char* baseStringStart = baseString;
- const char* pathStart = baseStringStart + base.m_portEnd;
- while (baseStringStart < pathStart)
- *bufferPos++ = *baseStringStart++;
- char* bufferPathStart = bufferPos;
-
- // now copy the base path
- const char* baseStringEnd = baseString + base.m_pathEnd;
-
- // go back to the last slash
- while (baseStringEnd > baseStringStart && baseStringEnd[-1] != '/')
- baseStringEnd--;
-
- if (baseStringEnd == baseStringStart) {
- // no path in base, add a path separator if necessary
- if (base.m_schemeEnd + 1 != base.m_pathEnd && *str && *str != '?' && *str != '#')
- *bufferPos++ = '/';
- } else {
- bufferPos += copyPathRemovingDots(bufferPos, baseStringStart, 0, baseStringEnd - baseStringStart);
- }
-
- const char* relStringStart = str;
- const char* relStringPos = relStringStart;
-
- while (*relStringPos && *relStringPos != '?' && *relStringPos != '#') {
- if (relStringPos[0] == '.' && bufferPos[-1] == '/') {
- if (isPathSegmentEndChar(relStringPos[1])) {
- // skip over "." segment
- relStringPos += 1;
- if (relStringPos[0] == '/')
- relStringPos++;
- continue;
- } else if (relStringPos[1] == '.' && isPathSegmentEndChar(relStringPos[2])) {
- // skip over ".." segment and rewind the last segment
- // the RFC leaves it up to the app to decide what to do with excess
- // ".." segments - we choose to drop them since some web content
- // relies on this.
- relStringPos += 2;
- if (relStringPos[0] == '/')
- relStringPos++;
- if (bufferPos > bufferPathStart + 1)
- bufferPos--;
- while (bufferPos > bufferPathStart + 1 && bufferPos[-1] != '/')
- bufferPos--;
- continue;
- }
- }
-
- *bufferPos = *relStringPos;
- relStringPos++;
- bufferPos++;
- }
-
- // all done with the path work, now copy any remainder
- // of the relative reference; this will also add a null terminator
- strcpy(bufferPos, relStringPos);
-
- parse(buffer.data(), 0);
-
- ASSERT(strlen(buffer.data()) + 1 <= buffer.size());
- break;
- }
- }
- }
-}
-
-bool KURL::hasPath() const
-{
- return m_pathEnd != m_portEnd;
-}
-
-String KURL::lastPathComponent() const
-{
- if (!hasPath())
- return String();
-
- int end = m_pathEnd - 1;
- if (m_string[end] == '/')
- --end;
-
- int start = m_string.reverseFind('/', end);
- if (start < m_portEnd)
- return String();
- ++start;
-
- return m_string.substring(start, end - start + 1);
-}
-
-String KURL::protocol() const
-{
- return m_string.left(m_schemeEnd);
-}
-
-String KURL::host() const
-{
- int start = hostStart();
- return decodeURLEscapeSequences(m_string.substring(start, m_hostEnd - start));
-}
-
-unsigned short KURL::port() const
-{
- if (m_hostEnd == m_portEnd)
- return 0;
-
- int number = m_string.substring(m_hostEnd + 1, m_portEnd - m_hostEnd - 1).toInt();
- if (number < 0 || number > 0xFFFF)
- return 0;
- return number;
-}
-
-String KURL::pass() const
-{
- if (m_passwordEnd == m_userEnd)
- return String();
-
- return decodeURLEscapeSequences(m_string.substring(m_userEnd + 1, m_passwordEnd - m_userEnd - 1));
-}
-
-String KURL::user() const
-{
- return decodeURLEscapeSequences(m_string.substring(m_userStart, m_userEnd - m_userStart));
-}
-
-String KURL::ref() const
-{
- if (m_fragmentEnd == m_queryEnd)
- return String();
-
- return m_string.substring(m_queryEnd + 1, m_fragmentEnd - (m_queryEnd + 1));
-}
-
-bool KURL::hasRef() const
-{
- return m_fragmentEnd != m_queryEnd;
-}
-
-static inline void assertProtocolIsGood(const char* protocol)
-{
-#ifndef NDEBUG
- const char* p = protocol;
- while (*p) {
- ASSERT(*p > ' ' && *p < 0x7F && !(*p >= 'A' && *p <= 'Z'));
- ++p;
- }
-#endif
-}
-
-bool KURL::protocolIs(const char* protocol) const
-{
- // Do the comparison without making a new string object.
- assertProtocolIsGood(protocol);
- if (!m_isValid)
- return false;
- for (int i = 0; i < m_schemeEnd; ++i) {
- if (!protocol[i] || toASCIILower(m_string[i]) != protocol[i])
- return false;
- }
- return !protocol[m_schemeEnd]; // We should have consumed all characters in the argument.
-}
-
-String KURL::query() const
-{
- return m_string.substring(m_pathEnd, m_queryEnd - m_pathEnd);
-}
-
-String KURL::path() const
-{
- return decodeURLEscapeSequences(m_string.substring(m_portEnd, m_pathEnd - m_portEnd));
-}
-
-void KURL::setProtocol(const String& s)
-{
- if (!m_isValid) {
- parse(s + ":" + m_string);
- return;
- }
-
- parse(s + m_string.substring(m_schemeEnd));
-}
-
-void KURL::setHost(const String& s)
-{
- if (!m_isValid)
- return;
-
- bool slashSlashNeeded = m_userStart == m_schemeEnd + 1;
-
- parse(m_string.left(hostStart()) + (slashSlashNeeded ? "//" : "") + s + m_string.substring(m_hostEnd));
-}
-
-void KURL::setPort(unsigned short i)
-{
- if (!m_isValid)
- return;
-
- bool colonNeeded = m_portEnd == m_hostEnd;
- int portStart = (colonNeeded ? m_hostEnd : m_hostEnd + 1);
-
- parse(m_string.left(portStart) + (colonNeeded ? ":" : "") + String::number(i) + m_string.substring(m_portEnd));
-}
-
-void KURL::setHostAndPort(const String& hostAndPort)
-{
- if (!m_isValid)
- return;
-
- bool slashSlashNeeded = m_userStart == m_schemeEnd + 1;
-
- parse(m_string.left(hostStart()) + (slashSlashNeeded ? "//" : "") + hostAndPort + m_string.substring(m_portEnd));
-}
-
-void KURL::setUser(const String& user)
-{
- if (!m_isValid)
- return;
-
- String u;
- int end = m_userEnd;
- if (!user.isEmpty()) {
- u = user;
- if (m_userStart == m_schemeEnd + 1)
- u = "//" + u;
- // Add '@' if we didn't have one before.
- if (end == m_hostEnd || (end == m_passwordEnd && m_string[end] != '@'))
- u.append('@');
- } else {
- // Remove '@' if we now have neither user nor password.
- if (m_userEnd == m_passwordEnd && end != m_hostEnd && m_string[end] == '@')
- end += 1;
- }
- parse(m_string.left(m_userStart) + u + m_string.substring(end));
-}
-
-void KURL::setPass(const String& password)
-{
- if (!m_isValid)
- return;
-
- String p;
- int end = m_passwordEnd;
- if (!password.isEmpty()) {
- p = ":" + password + "@";
- if (m_userEnd == m_schemeEnd + 1)
- p = "//" + p;
- // Eat the existing '@' since we are going to add our own.
- if (end != m_hostEnd && m_string[end] == '@')
- end += 1;
- } else {
- // Remove '@' if we now have neither user nor password.
- if (m_userStart == m_userEnd && end != m_hostEnd && m_string[end] == '@')
- end += 1;
- }
- parse(m_string.left(m_userEnd) + p + m_string.substring(end));
-}
-
-void KURL::setRef(const String& s)
-{
- if (!m_isValid)
- return;
- parse(m_string.left(m_queryEnd) + (s.isNull() ? "" : "#" + s));
-}
-
-void KURL::removeRef()
-{
- if (!m_isValid)
- return;
- parse(m_string.left(m_queryEnd));
-}
-
-void KURL::setQuery(const String& query)
-{
- if (!m_isValid)
- return;
-
- if ((query.isEmpty() || query[0] != '?') && !query.isNull())
- parse(m_string.left(m_pathEnd) + "?" + query + m_string.substring(m_queryEnd));
- else
- parse(m_string.left(m_pathEnd) + query + m_string.substring(m_queryEnd));
-
-}
-
-void KURL::setPath(const String& s)
-{
- if (!m_isValid)
- return;
-
- parse(m_string.left(m_portEnd) + encodeWithURLEscapeSequences(s) + m_string.substring(m_pathEnd));
-}
-
-String KURL::prettyURL() const
-{
- if (!m_isValid)
- return m_string;
-
- Vector<UChar> result;
-
- append(result, protocol());
- result.append(':');
-
- Vector<UChar> authority;
-
- if (m_hostEnd != m_passwordEnd) {
- if (m_userEnd != m_userStart) {
- append(authority, user());
- authority.append('@');
- }
- append(authority, host());
- if (port() != 0) {
- authority.append(':');
- append(authority, String::number(port()));
- }
- }
-
- if (!authority.isEmpty()) {
- result.append('/');
- result.append('/');
- result.append(authority);
- } else if (protocolIs("file")) {
- result.append('/');
- result.append('/');
- }
-
- append(result, path());
- append(result, query());
-
- if (m_fragmentEnd != m_queryEnd) {
- result.append('#');
- append(result, ref());
- }
-
- return String::adopt(result);
-}
-
-#ifdef KURL_DECORATE_GLOBALS
-String KURL::decodeURLEscapeSequences(const String& str)
-#else
-String decodeURLEscapeSequences(const String& str)
-#endif
-{
- return decodeURLEscapeSequences(str, UTF8Encoding());
-}
-
-#ifdef KURL_DECORATE_GLOBALS
-String KURL::decodeURLEscapeSequences(const String& str, const TextEncoding& encoding)
-#else
-String decodeURLEscapeSequences(const String& str, const TextEncoding& encoding)
-#endif
-{
- Vector<UChar> result;
-
- CharBuffer buffer;
-
- int length = str.length();
- int decodedPosition = 0;
- int searchPosition = 0;
- int encodedRunPosition;
- while ((encodedRunPosition = str.find('%', searchPosition)) >= 0) {
- // Find the sequence of %-escape codes.
- int encodedRunEnd = encodedRunPosition;
- while (length - encodedRunEnd >= 3
- && str[encodedRunEnd] == '%'
- && isASCIIHexDigit(str[encodedRunEnd + 1])
- && isASCIIHexDigit(str[encodedRunEnd + 2]))
- encodedRunEnd += 3;
- if (encodedRunEnd == encodedRunPosition) {
- ++searchPosition;
- continue;
- }
- searchPosition = encodedRunEnd;
-
- // Decode the %-escapes into bytes.
- unsigned runLength = (encodedRunEnd - encodedRunPosition) / 3;
- buffer.resize(runLength);
- char* p = buffer.data();
- const UChar* q = str.characters() + encodedRunPosition;
- for (unsigned i = 0; i < runLength; ++i) {
- *p++ = (hexDigitValue(q[1]) << 4) | hexDigitValue(q[2]);
- q += 3;
- }
-
- // Decode the bytes into Unicode characters.
- String decoded = (encoding.isValid() ? encoding : UTF8Encoding()).decode(buffer.data(), p - buffer.data());
- if (decoded.isEmpty())
- continue;
-
- // Build up the string with what we just skipped and what we just decoded.
- result.append(str.characters() + decodedPosition, encodedRunPosition - decodedPosition);
- result.append(decoded.characters(), decoded.length());
- decodedPosition = encodedRunEnd;
- }
-
- result.append(str.characters() + decodedPosition, length - decodedPosition);
-
- return String::adopt(result);
-}
-
-bool KURL::isLocalFile() const
-{
- // Including feed here might be a bad idea since drag and drop uses this check
- // and including feed would allow feeds to potentially let someone's blog
- // read the contents of the clipboard on a drag, even without a drop.
- // Likewise with using the FrameLoader::shouldTreatURLAsLocal() function.
- return protocolIs("file");
-}
-
-static void appendEscapingBadChars(char*& buffer, const char* strStart, size_t length)
-{
- char* p = buffer;
-
- const char* str = strStart;
- const char* strEnd = strStart + length;
- while (str < strEnd) {
- unsigned char c = *str++;
- if (isBadChar(c)) {
- if (c == '%' || c == '?') {
- *p++ = c;
- } else if (c != 0x09 && c != 0x0a && c != 0x0d) {
- *p++ = '%';
- *p++ = hexDigits[c >> 4];
- *p++ = hexDigits[c & 0xF];
- }
- } else {
- *p++ = c;
- }
- }
-
- buffer = p;
-}
-
-// copy a path, accounting for "." and ".." segments
-static int copyPathRemovingDots(char* dst, const char* src, int srcStart, int srcEnd)
-{
- char* bufferPathStart = dst;
-
- // empty path is a special case, and need not have a leading slash
- if (srcStart != srcEnd) {
- const char* baseStringStart = src + srcStart;
- const char* baseStringEnd = src + srcEnd;
- const char* baseStringPos = baseStringStart;
-
- // this code is unprepared for paths that do not begin with a
- // slash and we should always have one in the source string
- ASSERT(baseStringPos[0] == '/');
-
- // copy the leading slash into the destination
- *dst = *baseStringPos;
- baseStringPos++;
- dst++;
-
- while (baseStringPos < baseStringEnd) {
- if (baseStringPos[0] == '.' && dst[-1] == '/') {
- if (baseStringPos[1] == '/' || baseStringPos + 1 == baseStringEnd) {
- // skip over "." segment
- baseStringPos += 2;
- continue;
- } else if (baseStringPos[1] == '.' && (baseStringPos[2] == '/' ||
- baseStringPos + 2 == baseStringEnd)) {
- // skip over ".." segment and rewind the last segment
- // the RFC leaves it up to the app to decide what to do with excess
- // ".." segments - we choose to drop them since some web content
- // relies on this.
- baseStringPos += 3;
- if (dst > bufferPathStart + 1)
- dst--;
- // Note that these two while blocks differ subtly.
- // The first helps to remove multiple adjoining slashes as we rewind.
- // The +1 to bufferPathStart in the first while block prevents eating a leading slash
- while (dst > bufferPathStart + 1 && dst[-1] == '/')
- dst--;
- while (dst > bufferPathStart && dst[-1] != '/')
- dst--;
- continue;
- }
- }
-
- *dst = *baseStringPos;
- baseStringPos++;
- dst++;
- }
- }
- *dst = '\0';
- return dst - bufferPathStart;
-}
-
-static inline bool hasSlashDotOrDotDot(const char* str)
-{
- const unsigned char* p = reinterpret_cast<const unsigned char*>(str);
- if (!*p)
- return false;
- unsigned char pc = *p;
- while (unsigned char c = *++p) {
- if (c == '.' && (pc == '/' || pc == '.'))
- return true;
- pc = c;
- }
- return false;
-}
-
-static inline bool matchLetter(char c, char lowercaseLetter)
-{
- return (c | 0x20) == lowercaseLetter;
-}
-
-void KURL::parse(const String& string)
-{
- CharBuffer buffer;
- encodeRelativeString(string, UTF8Encoding(), buffer);
- parse(buffer.data(), &string);
-}
-
-void KURL::parse(const char* url, const String* originalString)
-{
- if (!url || url[0] == '\0') {
- // valid URL must be non-empty
- m_string = originalString ? *originalString : url;
- invalidate();
- return;
- }
-
- if (!isSchemeFirstChar(url[0])) {
- // scheme must start with an alphabetic character
- m_string = originalString ? *originalString : url;
- invalidate();
- return;
- }
-
- int schemeEnd = 0;
- while (isSchemeChar(url[schemeEnd]))
- schemeEnd++;
-
- if (url[schemeEnd] != ':') {
- m_string = originalString ? *originalString : url;
- invalidate();
- return;
- }
-
- int userStart = schemeEnd + 1;
- int userEnd;
- int passwordStart;
- int passwordEnd;
- int hostStart;
- int hostEnd;
- int portStart;
- int portEnd;
-
- bool hierarchical = url[schemeEnd + 1] == '/';
-
- bool isFile = schemeEnd == 4
- && matchLetter(url[0], 'f')
- && matchLetter(url[1], 'i')
- && matchLetter(url[2], 'l')
- && matchLetter(url[3], 'e');
-
- bool isHTTPorHTTPS = matchLetter(url[0], 'h')
- && matchLetter(url[1], 't')
- && matchLetter(url[2], 't')
- && matchLetter(url[3], 'p')
- && (url[4] == ':' || (matchLetter(url[4], 's') && url[5] == ':'));
-
- if (hierarchical && url[schemeEnd + 2] == '/') {
- // The part after the scheme is either a net_path or an abs_path whose first path segment is empty.
- // Attempt to find an authority.
-
- // FIXME: Authority characters may be scanned twice, and it would be nice to be faster.
- userStart += 2;
- userEnd = userStart;
-
- int colonPos = 0;
- while (isUserInfoChar(url[userEnd])) {
- if (url[userEnd] == ':' && colonPos == 0)
- colonPos = userEnd;
- userEnd++;
- }
-
- if (url[userEnd] == '@') {
- // actual end of the userinfo, start on the host
- if (colonPos != 0) {
- passwordEnd = userEnd;
- userEnd = colonPos;
- passwordStart = colonPos + 1;
- } else
- passwordStart = passwordEnd = userEnd;
-
- hostStart = passwordEnd + 1;
- } else if (url[userEnd] == '[' || isPathSegmentEndChar(url[userEnd])) {
- // hit the end of the authority, must have been no user
- // or looks like an IPv6 hostname
- // either way, try to parse it as a hostname
- userEnd = userStart;
- passwordStart = passwordEnd = userEnd;
- hostStart = userStart;
- } else {
- // invalid character
- m_string = originalString ? *originalString : url;
- invalidate();
- return;
- }
-
- hostEnd = hostStart;
-
- // IPV6 IP address
- if (url[hostEnd] == '[') {
- hostEnd++;
- while (isIPv6Char(url[hostEnd]))
- hostEnd++;
- if (url[hostEnd] == ']')
- hostEnd++;
- else {
- // invalid character
- m_string = originalString ? *originalString : url;
- invalidate();
- return;
- }
- } else {
- while (isHostnameChar(url[hostEnd]))
- hostEnd++;
- }
-
- if (url[hostEnd] == ':') {
- portStart = portEnd = hostEnd + 1;
-
- // possible start of port
- portEnd = portStart;
- while (isASCIIDigit(url[portEnd]))
- portEnd++;
- } else
- portStart = portEnd = hostEnd;
-
- if (!isPathSegmentEndChar(url[portEnd])) {
- // invalid character
- m_string = originalString ? *originalString : url;
- invalidate();
- return;
- }
-
- if (userStart == portEnd && !isHTTPorHTTPS && !isFile) {
- // No authority found, which means that this is not a net_path, but rather an abs_path whose first two
- // path segments are empty. For file, http and https only, an empty authority is allowed.
- userStart -= 2;
- userEnd = userStart;
- passwordStart = userEnd;
- passwordEnd = passwordStart;
- hostStart = passwordEnd;
- hostEnd = hostStart;
- portStart = hostEnd;
- portEnd = hostEnd;
- }
- } else {
- // the part after the scheme must be an opaque_part or an abs_path
- userEnd = userStart;
- passwordStart = passwordEnd = userEnd;
- hostStart = hostEnd = passwordEnd;
- portStart = portEnd = hostEnd;
- }
-
- int pathStart = portEnd;
- int pathEnd = pathStart;
- while (url[pathEnd] && url[pathEnd] != '?' && url[pathEnd] != '#')
- pathEnd++;
-
- int queryStart = pathEnd;
- int queryEnd = queryStart;
- if (url[queryStart] == '?') {
- while (url[queryEnd] && url[queryEnd] != '#')
- queryEnd++;
- }
-
- int fragmentStart = queryEnd;
- int fragmentEnd = fragmentStart;
- if (url[fragmentStart] == '#') {
- fragmentStart++;
- fragmentEnd = fragmentStart;
- while (url[fragmentEnd])
- fragmentEnd++;
- }
-
- // assemble it all, remembering the real ranges
-
- Vector<char, 4096> buffer(fragmentEnd * 3 + 1);
-
- char *p = buffer.data();
- const char *strPtr = url;
-
- // copy in the scheme
- const char *schemeEndPtr = url + schemeEnd;
- while (strPtr < schemeEndPtr)
- *p++ = *strPtr++;
- m_schemeEnd = p - buffer.data();
-
- bool hostIsLocalHost = portEnd - userStart == 9
- && matchLetter(url[userStart], 'l')
- && matchLetter(url[userStart+1], 'o')
- && matchLetter(url[userStart+2], 'c')
- && matchLetter(url[userStart+3], 'a')
- && matchLetter(url[userStart+4], 'l')
- && matchLetter(url[userStart+5], 'h')
- && matchLetter(url[userStart+6], 'o')
- && matchLetter(url[userStart+7], 's')
- && matchLetter(url[userStart+8], 't');
-
- // File URLs need a host part unless it is just file:// or file://localhost
- bool degenFilePath = pathStart == pathEnd && (hostStart == hostEnd || hostIsLocalHost);
-
- bool haveNonHostAuthorityPart = userStart != userEnd || passwordStart != passwordEnd || portStart != portEnd;
-
- // add ":" after scheme
- *p++ = ':';
-
- // if we have at least one authority part or a file URL - add "//" and authority
- if (isFile ? !degenFilePath : (haveNonHostAuthorityPart || hostStart != hostEnd)) {
- *p++ = '/';
- *p++ = '/';
-
- m_userStart = p - buffer.data();
-
- // copy in the user
- strPtr = url + userStart;
- const char* userEndPtr = url + userEnd;
- while (strPtr < userEndPtr)
- *p++ = *strPtr++;
- m_userEnd = p - buffer.data();
-
- // copy in the password
- if (passwordEnd != passwordStart) {
- *p++ = ':';
- strPtr = url + passwordStart;
- const char* passwordEndPtr = url + passwordEnd;
- while (strPtr < passwordEndPtr)
- *p++ = *strPtr++;
- }
- m_passwordEnd = p - buffer.data();
-
- // If we had any user info, add "@"
- if (p - buffer.data() != m_userStart)
- *p++ = '@';
-
- // copy in the host, except in the case of a file URL with authority="localhost"
- if (!(isFile && hostIsLocalHost && !haveNonHostAuthorityPart)) {
- strPtr = url + hostStart;
- const char* hostEndPtr = url + hostEnd;
- while (strPtr < hostEndPtr)
- *p++ = *strPtr++;
- }
- m_hostEnd = p - buffer.data();
-
- // copy in the port
- if (hostEnd != portStart) {
- *p++ = ':';
- strPtr = url + portStart;
- const char *portEndPtr = url + portEnd;
- while (strPtr < portEndPtr)
- *p++ = *strPtr++;
- }
- m_portEnd = p - buffer.data();
- } else
- m_userStart = m_userEnd = m_passwordEnd = m_hostEnd = m_portEnd = p - buffer.data();
-
- // For canonicalization, ensure we have a '/' for no path.
- // Only do this for http and https.
- if (isHTTPorHTTPS && pathEnd - pathStart == 0)
- *p++ = '/';
-
- // add path, escaping bad characters
- if (!hierarchical || !hasSlashDotOrDotDot(url))
- appendEscapingBadChars(p, url + pathStart, pathEnd - pathStart);
- else {
- CharBuffer pathBuffer(pathEnd - pathStart + 1);
- size_t length = copyPathRemovingDots(pathBuffer.data(), url, pathStart, pathEnd);
- appendEscapingBadChars(p, pathBuffer.data(), length);
- }
-
- m_pathEnd = p - buffer.data();
-
- // Find the position after the last slash in the path, or
- // the position before the path if there are no slashes in it.
- int i;
- for (i = m_pathEnd; i > m_portEnd; --i) {
- if (buffer[i - 1] == '/')
- break;
- }
- m_pathAfterLastSlash = i;
-
- // add query, escaping bad characters
- appendEscapingBadChars(p, url + queryStart, queryEnd - queryStart);
- m_queryEnd = p - buffer.data();
-
- // add fragment, escaping bad characters
- if (fragmentEnd != queryEnd) {
- *p++ = '#';
- appendEscapingBadChars(p, url + fragmentStart, fragmentEnd - fragmentStart);
- }
- m_fragmentEnd = p - buffer.data();
-
- ASSERT(p - buffer.data() <= static_cast<int>(buffer.size()));
-
- // If we didn't end up actually changing the original string and
- // it was already in a String, reuse it to avoid extra allocation.
- if (originalString && strncmp(buffer.data(), url, m_fragmentEnd) == 0)
- m_string = *originalString;
- else
- m_string = String(buffer.data(), m_fragmentEnd);
-
- m_isValid = true;
-}
-
-bool equalIgnoringRef(const KURL& a, const KURL& b)
-{
- if (a.m_queryEnd != b.m_queryEnd)
- return false;
- unsigned queryLength = a.m_queryEnd;
- for (unsigned i = 0; i < queryLength; ++i)
- if (a.string()[i] != b.string()[i])
- return false;
- return true;
-}
-
-bool protocolHostAndPortAreEqual(const KURL& a, const KURL& b)
-{
- if (a.m_schemeEnd != b.m_schemeEnd)
- return false;
- int hostStartA = a.hostStart();
- int hostStartB = b.hostStart();
- if (a.m_hostEnd - hostStartA != b.m_hostEnd - hostStartB)
- return false;
-
- // Check the scheme
- for (int i = 0; i < a.m_schemeEnd; ++i)
- if (a.string()[i] != b.string()[i])
- return false;
-
- // And the host
- for (int i = hostStartA; i < a.m_hostEnd; ++i)
- if (a.string()[i] != b.string()[i])
- return false;
-
- if (a.port() != b.port())
- return false;
-
- return true;
-}
-
-#ifdef KURL_DECORATE_GLOBALS
-String KURL::encodeWithURLEscapeSequences(const String& notEncodedString)
-#else
-String encodeWithURLEscapeSequences(const String& notEncodedString)
-#endif
-{
- CString asUTF8 = notEncodedString.utf8();
-
- CharBuffer buffer(asUTF8.length() * 3 + 1);
- char* p = buffer.data();
-
- const char* str = asUTF8.data();
- const char* strEnd = str + asUTF8.length();
- while (str < strEnd) {
- unsigned char c = *str++;
- if (isBadChar(c)) {
- *p++ = '%';
- *p++ = hexDigits[c >> 4];
- *p++ = hexDigits[c & 0xF];
- } else
- *p++ = c;
- }
-
- ASSERT(p - buffer.data() <= static_cast<int>(buffer.size()));
-
- return String(buffer.data(), p - buffer.data());
-}
-
-// Appends the punycoded hostname identified by the given string and length to
-// the output buffer. The result will not be null terminated.
-static void appendEncodedHostname(UCharBuffer& buffer, const UChar* str, unsigned strLen)
-{
- // Needs to be big enough to hold an IDN-encoded name.
- // For host names bigger than this, we won't do IDN encoding, which is almost certainly OK.
- const unsigned hostnameBufferLength = 2048;
-
- if (strLen > hostnameBufferLength || charactersAreAllASCII(str, strLen)) {
- buffer.append(str, strLen);
- return;
- }
-
-#if USE(ICU_UNICODE)
- UChar hostnameBuffer[hostnameBufferLength];
- UErrorCode error = U_ZERO_ERROR;
- int32_t numCharactersConverted = uidna_IDNToASCII(str, strLen, hostnameBuffer,
- hostnameBufferLength, UIDNA_ALLOW_UNASSIGNED, 0, &error);
- if (error == U_ZERO_ERROR)
- buffer.append(hostnameBuffer, numCharactersConverted);
-#elif USE(QT4_UNICODE)
- QByteArray result = QUrl::toAce(String(str, strLen));
- buffer.append(result.constData(), result.length());
-#endif
-}
-
-static void findHostnamesInMailToURL(const UChar* str, int strLen, Vector<pair<int, int> >& nameRanges)
-{
- // In a mailto: URL, host names come after a '@' character and end with a '>' or ',' or '?' or end of string character.
- // Skip quoted strings so that characters in them don't confuse us.
- // When we find a '?' character, we are past the part of the URL that contains host names.
-
- nameRanges.clear();
-
- int p = 0;
- while (1) {
- // Find start of host name or of quoted string.
- int hostnameOrStringStart = findFirstOf(str, strLen, p, "\"@?");
- if (hostnameOrStringStart == -1)
- return;
- UChar c = str[hostnameOrStringStart];
- p = hostnameOrStringStart + 1;
-
- if (c == '?')
- return;
-
- if (c == '@') {
- // Find end of host name.
- int hostnameStart = p;
- int hostnameEnd = findFirstOf(str, strLen, p, ">,?");
- bool done;
- if (hostnameEnd == -1) {
- hostnameEnd = strLen;
- done = true;
- } else {
- p = hostnameEnd;
- done = false;
- }
-
- nameRanges.append(make_pair(hostnameStart, hostnameEnd));
-
- if (done)
- return;
- } else {
- // Skip quoted string.
- ASSERT(c == '"');
- while (1) {
- int escapedCharacterOrStringEnd = findFirstOf(str, strLen, p, "\"\\");
- if (escapedCharacterOrStringEnd == -1)
- return;
-
- c = str[escapedCharacterOrStringEnd];
- p = escapedCharacterOrStringEnd + 1;
-
- // If we are the end of the string, then break from the string loop back to the host name loop.
- if (c == '"')
- break;
-
- // Skip escaped character.
- ASSERT(c == '\\');
- if (p == strLen)
- return;
-
- ++p;
- }
- }
- }
-}
-
-static bool findHostnameInHierarchicalURL(const UChar* str, int strLen, int& startOffset, int& endOffset)
-{
- // Find the host name in a hierarchical URL.
- // It comes after a "://" sequence, with scheme characters preceding, and
- // this should be the first colon in the string.
- // It ends with the end of the string or a ":" or a path segment ending character.
- // If there is a "@" character, the host part is just the part after the "@".
- int separator = findFirstOf(str, strLen, 0, ":");
- if (separator == -1 || separator + 2 >= strLen ||
- str[separator + 1] != '/' || str[separator + 2] != '/')
- return false;
-
- // Check that all characters before the :// are valid scheme characters.
- if (!isSchemeFirstChar(str[0]))
- return false;
- for (int i = 1; i < separator; ++i) {
- if (!isSchemeChar(str[i]))
- return false;
- }
-
- // Start after the separator.
- int authorityStart = separator + 3;
-
- // Find terminating character.
- int hostnameEnd = strLen;
- for (int i = authorityStart; i < strLen; ++i) {
- UChar c = str[i];
- if (c == ':' || (isPathSegmentEndChar(c) && c != 0)) {
- hostnameEnd = i;
- break;
- }
- }
-
- // Find "@" for the start of the host name.
- int userInfoTerminator = findFirstOf(str, strLen, authorityStart, "@");
- int hostnameStart;
- if (userInfoTerminator == -1 || userInfoTerminator > hostnameEnd)
- hostnameStart = authorityStart;
- else
- hostnameStart = userInfoTerminator + 1;
-
- startOffset = hostnameStart;
- endOffset = hostnameEnd;
- return true;
-}
-
-// Converts all hostnames found in the given input to punycode, preserving the
-// rest of the URL unchanged. The output will NOT be null-terminated.
-static void encodeHostnames(const String& str, UCharBuffer& output)
-{
- output.clear();
-
- if (KURL::protocolIs(str, "mailto")) {
- Vector<pair<int, int> > hostnameRanges;
- findHostnamesInMailToURL(str.characters(), str.length(), hostnameRanges);
- int n = hostnameRanges.size();
- int p = 0;
- for (int i = 0; i < n; ++i) {
- const pair<int, int>& r = hostnameRanges[i];
- output.append(&str.characters()[p], r.first - p);
- appendEncodedHostname(output, &str.characters()[r.first], r.second - r.first);
- p = r.second;
- }
- // This will copy either everything after the last hostname, or the
- // whole thing if there is no hostname.
- output.append(&str.characters()[p], str.length() - p);
- } else {
- int hostStart, hostEnd;
- if (findHostnameInHierarchicalURL(str.characters(), str.length(), hostStart, hostEnd)) {
- output.append(str.characters(), hostStart); // Before hostname.
- appendEncodedHostname(output, &str.characters()[hostStart], hostEnd - hostStart);
- output.append(&str.characters()[hostEnd], str.length() - hostEnd); // After hostname.
- } else {
- // No hostname to encode, return the input.
- output.append(str.characters(), str.length());
- }
- }
-}
-
-static void encodeRelativeString(const String& rel, const TextEncoding& encoding, CharBuffer& output)
-{
- UCharBuffer s;
- encodeHostnames(rel, s);
-
- TextEncoding pathEncoding(UTF8Encoding()); // Path is always encoded as UTF-8; other parts may depend on the scheme.
-
- int pathEnd = -1;
- if (encoding != pathEncoding && encoding.isValid() && !KURL::protocolIs(rel, "mailto") && !KURL::protocolIs(rel, "data")) {
- // Find the first instance of either # or ?, keep pathEnd at -1 otherwise.
- pathEnd = findFirstOf(s.data(), s.size(), 0, "#?");
- }
-
- if (pathEnd == -1) {
- CString decoded = pathEncoding.encode(s.data(), s.size(), URLEncodedEntitiesForUnencodables);
- output.resize(decoded.length());
- memcpy(output.data(), decoded.data(), decoded.length());
- } else {
- CString pathDecoded = pathEncoding.encode(s.data(), pathEnd, URLEncodedEntitiesForUnencodables);
- // Unencodable characters in URLs are represented by converting
- // them to XML entities and escaping non-alphanumeric characters.
- CString otherDecoded = encoding.encode(s.data() + pathEnd, s.size() - pathEnd, URLEncodedEntitiesForUnencodables);
-
- output.resize(pathDecoded.length() + otherDecoded.length());
- memcpy(output.data(), pathDecoded.data(), pathDecoded.length());
- memcpy(output.data() + pathDecoded.length(), otherDecoded.data(), otherDecoded.length());
- }
- output.append('\0'); // null-terminate the output.
-}
-
-static String substituteBackslashes(const String& string)
-{
- int questionPos = string.find('?');
- int hashPos = string.find('#');
- int pathEnd;
-
- if (hashPos >= 0 && (questionPos < 0 || questionPos > hashPos))
- pathEnd = hashPos;
- else if (questionPos >= 0)
- pathEnd = questionPos;
- else
- pathEnd = string.length();
-
- return string.left(pathEnd).replace('\\','/') + string.substring(pathEnd);
-}
-
-bool KURL::isHierarchical() const
-{
- if (!m_isValid)
- return false;
- ASSERT(m_string[m_schemeEnd] == ':');
- return m_string[m_schemeEnd + 1] == '/';
-}
-
-void KURL::copyToBuffer(CharBuffer& buffer) const
-{
- // FIXME: This throws away the high bytes of all the characters in the string!
- // That's fine for a valid URL, which is all ASCII, but not for invalid URLs.
- buffer.resize(m_string.length());
- copyASCII(m_string.characters(), m_string.length(), buffer.data());
-}
-
-#ifdef KURL_DECORATE_GLOBALS
-bool KURL::protocolIs(const String& url, const char* protocol)
-#else
-bool protocolIs(const String& url, const char* protocol)
-#endif
-{
- // Do the comparison without making a new string object.
- assertProtocolIsGood(protocol);
- for (int i = 0; ; ++i) {
- if (!protocol[i])
- return url[i] == ':';
- if (toASCIILower(url[i]) != protocol[i])
- return false;
- }
-}
-
-#ifdef KURL_DECORATE_GLOBALS
-String KURL::mimeTypeFromDataURL(const String& url)
-#else
-String mimeTypeFromDataURL(const String& url)
-#endif
-{
- ASSERT(protocolIs(url, "data"));
- int index = url.find(';');
- if (index == -1)
- index = url.find(',');
- if (index != -1) {
- int len = index - 5;
- if (len > 0)
- return url.substring(5, len);
- return "text/plain"; // Data URLs with no MIME type are considered text/plain.
- }
- return "";
-}
-
-#ifdef KURL_DECORATE_GLOBALS
-const KURL& KURL::blankURL()
-#else
-const KURL& blankURL()
-#endif
-{
- static KURL staticBlankURL("about:blank");
- return staticBlankURL;
-}
-
-#ifndef NDEBUG
-void KURL::print() const
-{
- printf("%s\n", m_string.utf8().data());
-}
-#endif
-
-}
-
-#endif // #ifndef USE_GOOGLE_URL_LIBRARY
diff --git a/webkit/pending/KURL.h b/webkit/pending/KURL.h
deleted file mode 100644
index b7c4cb2..0000000
--- a/webkit/pending/KURL.h
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef KURL_h
-#define KURL_h
-
-#include "PlatformString.h"
-
-#ifdef USE_GOOGLE_URL_LIBRARY
-#include "CString.h"
-#include "googleurl/src/url_canon.h"
-#include "googleurl/src/url_parse.h"
-// TODO(brettw): Crazy hack. Because these headers pull in base/basictypes.h,
-// which redefines COMPILE_ASSERT, restore it here to the definition in
-// wtf/Assertions.h.
-#undef COMPILE_ASSERT
-#define COMPILE_ASSERT(exp, name) typedef int dummy##name [(exp) ? 1 : -1];
-#endif
-
-#if PLATFORM(CF)
-typedef const struct __CFURL* CFURLRef;
-#endif
-
-#if PLATFORM(MAC)
-#ifdef __OBJC__
-@class NSURL;
-#else
-class NSURL;
-#endif
-#endif
-
-#if PLATFORM(QT)
-QT_BEGIN_NAMESPACE
-class QUrl;
-QT_END_NAMESPACE
-#endif
-
-namespace WebCore {
-
-class TextEncoding;
-struct KURLHash;
-
-// FIXME: Our terminology here is a bit inconsistent. We refer to the part
-// after the "#" as the "fragment" in some places and the "ref" in others.
-// We should fix the terminology to match the URL and URI RFCs as closely
-// as possible to resolve this.
-
-class KURL {
-public:
- // Generates a URL which contains a null string.
- KURL() { invalidate(); }
-
- // The argument is an absolute URL string. The string is assumed to be
- // already encoded.
- // FIXME: This constructor has a special case for strings that start with
- // "/", prepending "file://" to such strings; it would be good to get
- // rid of that special case.
- explicit KURL(const char*);
-
- // The argument is an absolute URL string. The string is assumed to be
- // already encoded.
- // FIXME: For characters with codes other than 0000-00FF will be chopped
- // off, so this call is currently not safe to use with arbitrary strings.
- // FIXME: This constructor has a special case for strings that start with
- // "/", prepending "file://" to such strings; it would be good to get
- // rid of that special case.
- explicit KURL(const String&);
-
- // Resolves the relative URL with the given base URL. If provided, the
- // TextEncoding is used to encode non-ASCII characers. The base URL can be
- // null or empty, in which case the relative URL will be interpreted as
- // absolute.
- // FIXME: If the base URL is invalid, this always creates an invalid
- // URL. Instead I think it would be better to treat all invalid base URLs
- // the same way we treate null and empty base URLs.
- KURL(const KURL& base, const String& relative);
- KURL(const KURL& base, const String& relative, const TextEncoding&);
-
- // FIXME: The above functions should be harmonized so that passing a
- // base of null or the empty string gives the same result as the
- // standard String constructor.
-#ifdef USE_GOOGLE_URL_LIBRARY
- // For conversions for other structures that have already parsed and
- // canonicalized the URL. The input must be exactly what KURL would have
- // done with the same input.
- KURL(const char* canonical_spec, int canonical_spec_len,
- const url_parse::Parsed& parsed, bool is_valid);
-#endif
-
- bool isValid() const { return m_isValid; }
-
- // Returns true if this URL has a path. Note that "http://foo.com/" has a
- // path of "/", so this function will return true. Only invalid or
- // non-hierarchical (like "javascript:") URLs will have no path.
- bool hasPath() const;
-
-#ifdef USE_GOOGLE_URL_LIBRARY
- bool isNull() const { return m_url.utf8String().isNull(); }
- bool isEmpty() const { return m_url.utf8String().length() == 0; }
-
- const String& string() const { return m_url.string(); }
-#else
- bool isNull() const { return m_string.isNull(); }
- bool isEmpty() const { return m_string.isEmpty(); }
-
- const String& string() const { return m_string; }
-#endif
-
- String protocol() const;
- String host() const;
- unsigned short port() const;
- String user() const;
- String pass() const;
- String path() const;
- String lastPathComponent() const;
- String query() const; // Includes the "?".
- String ref() const; // Does *not* include the "#".
- bool hasRef() const;
-
- String prettyURL() const;
- String fileSystemPath() const;
-
- // Returns true if the current URL's protocol is the same as the null-
- // terminated ASCII argument. The argument must be lower-case.
- bool protocolIs(const char*) const;
- bool isLocalFile() const;
-
- void setProtocol(const String&);
- void setHost(const String&);
-
- // Setting the port to 0 will clear any port from the URL.
- void setPort(unsigned short);
-
- // Input is like "foo.com" or "foo.com:8000".
- void setHostAndPort(const String&);
-
- void setUser(const String&);
- void setPass(const String&);
-
- // If you pass an empty path for HTTP or HTTPS URLs, the resulting path
- // will be "/".
- void setPath(const String&);
-
- // The query may begin with a question mark, or, if not, one will be added
- // for you. Setting the query to the empty string will leave a "?" in the
- // URL (with nothing after it). To clear the query, pass a null string.
- void setQuery(const String&);
-
- void setRef(const String&);
- void removeRef();
-
- friend bool equalIgnoringRef(const KURL&, const KURL&);
-
- friend bool protocolHostAndPortAreEqual(const KURL&, const KURL&);
-
- static bool protocolIs(const String&, const char*);
-
-#ifdef USE_GOOGLE_URL_LIBRARY
- operator const String&() const { return m_url.string(); }
-#if USE(JSC)
- operator KJS::UString() const { return m_url.string(); }
-#endif
-
- unsigned hostStart() const;
- unsigned hostEnd() const;
-
- unsigned pathStart() const;
- unsigned pathEnd() const;
- unsigned pathAfterLastSlash() const;
-
-#else // !USE_GOOGLE_URL_LIBRARY
- operator const String&() const { return m_string; }
-#if USE(JSC)
- operator KJS::UString() const { return m_string; }
-#endif
-
- unsigned hostStart() const { return (m_passwordEnd == m_userStart) ? m_passwordEnd : m_passwordEnd + 1; }
- unsigned hostEnd() const { return m_hostEnd; }
-
- unsigned pathStart() const { return m_portEnd; }
- unsigned pathEnd() const { return m_pathEnd; }
- unsigned pathAfterLastSlash() const { return m_pathAfterLastSlash; }
-#endif
-
-#if PLATFORM(CF)
- KURL(CFURLRef);
- CFURLRef createCFURL() const;
-#endif
-
-#if PLATFORM(MAC)
- KURL(NSURL*);
- operator NSURL*() const;
-#endif
-#ifdef __OBJC__
-#ifdef USE_GOOGLE_URL_LIBRARY
- operator NSString*() const { return string(); }
-#else // USE_GOOGLE_URL_LIBRARY
- operator NSString*() const { return m_string; }
-#endif // USE_GOOGLE_URL_LIBRARY
-#endif
-
-#if PLATFORM(QT)
- KURL(const QUrl&);
- operator QUrl() const;
-#endif
-
-#ifdef USE_GOOGLE_URL_LIBRARY
- // Getters for the parsed structure and its corresponding 8-bit string.
- const url_parse::Parsed& parsed() const { return m_parsed; }
- const CString& utf8String() const { return m_url.utf8String(); }
-#endif
-
-#ifndef NDEBUG
- void print() const;
-#endif
-
-private:
- void invalidate();
- bool isHierarchical() const;
-
- bool m_isValid;
-#ifdef USE_GOOGLE_URL_LIBRARY
- // Initializes the object. This will call through to one of the backend
- // initializers below depending on whether the string's internal
- // representation is 8 or 16 bit.
- void init(const KURL& base, const String& relative,
- const TextEncoding* query_encoding);
-
- // Backend initializers. The query encoding parameters are optional and can
- // be NULL (this implies UTF-8). These initializers require that the object
- // has just been created and the strings are NULL. Do not call on an
- // already-constructed object.
- void init(const KURL& base, const char* rel, int rel_len,
- const TextEncoding* query_encoding);
- void init(const KURL& base, const UChar* rel, int rel_len,
- const TextEncoding* query_encoding);
-
- // Returns the substring of the input identified by the given component.
- String componentString(const url_parse::Component& comp) const;
-
- // Replaces the given components, modifying the current URL. The current
- // URL must be valid.
- typedef url_canon::Replacements<url_parse::UTF16Char> Replacements;
- void replaceComponents(const Replacements& replacements);
-
- // Returns true if the scheme matches the given lowercase ASCII scheme.
- bool schemeIs(const char* lower_ascii_scheme) const;
-
- // We store the URL in UTF-8 (really, ASCII except for the ref which can be
- // UTF-8). WebKit wants Strings out of us.
- // We create the conversion of the strings on demand and cache the results
- // to speed things up.
- class URLString {
- public:
- URLString();
-
- // Setters for the data. Using the ASCII version when you know the
- // data is ASCII will be slightly more efficient. The UTF-8 version
- // will always be correct if the caller is unsure.
- void setUtf8(const char* data, int data_len);
- void setAscii(const char* data, int data_len);
-
- // TODO(brettw) we can support an additional optimization when KURL
- // class is supported only for Strings. Make this buffer support both
- // optinal Strings and UTF-8 data. This way, we can use the optimization
- // from the original KURL which uses = with the original string when
- // canonicalization did not change it. This allows the strings to share
- // a buffer internally, and saves a malloc.
-
- // Getters for the data.
- const CString& utf8String() const { return m_utf8; }
- const String& string() const;
-
- private:
- CString m_utf8;
-
- // Set to true when the caller set us using the ASCII setter. We can
- // be more efficient when we know there is no UTF-8 to worry about.
- // This flag is currently always correct, but should be changed to be a
- // hint (see setUtf8).
- bool m_utf8IsASCII;
-
- mutable bool m_stringIsValid;
- mutable String m_string;
- };
-
- URLString m_url;
- url_parse::Parsed m_parsed; // Indexes into the UTF-8 version of the string.
-
-#else
- void init(const KURL&, const String&, const TextEncoding&);
- void copyToBuffer(Vector<char, 512>& buffer) const;
-
- // Parses the given URL. The originalString parameter allows for an
- // optimization: When the source is the same as the fixed-up string,
- // it will use the passed-in string instead of allocating a new one.
- void parse(const String&);
- void parse(const char* url, const String* originalString);
-
- String m_string;
-
- int m_schemeEnd;
- int m_userStart;
- int m_userEnd;
- int m_passwordEnd;
- int m_hostEnd;
- int m_portEnd;
- int m_pathAfterLastSlash;
- int m_pathEnd;
- int m_queryEnd;
- int m_fragmentEnd;
-#endif
-
-// See the following "#infdef KURL_DECORATE_GLOBALS" for an explanation.
-#ifdef KURL_DECORATE_GLOBALS
- public:
- static const KURL& blankURL();
- // Note: protocolIs() is already defined, so omit it.
- static String mimeTypeFromDataURL(const String& url);
- static String decodeURLEscapeSequences(const String&);
- static String decodeURLEscapeSequences(const String&, const TextEncoding&);
- static String encodeWithURLEscapeSequences(const String&);
-#endif // ifdef KURL_DECORATE_GLOBALS
-};
-
-bool operator==(const KURL&, const KURL&);
-bool operator==(const KURL&, const String&);
-bool operator==(const String&, const KURL&);
-bool operator!=(const KURL&, const KURL&);
-bool operator!=(const KURL&, const String&);
-bool operator!=(const String&, const KURL&);
-
-bool equalIgnoringRef(const KURL&, const KURL&);
-bool protocolHostAndPortAreEqual(const KURL&, const KURL&);
-
-// GKURL_unittest.cpp includes both KURL.cpp and GKURL.cpp.
-// For that to work, global functions need to be avoided.
-// (the other globals are okay since they include KURL in parameter list).
-// The workaround is to move the globals into KURL's class namespace.
-#ifndef KURL_DECORATE_GLOBALS
-
-const KURL& blankURL();
-
-// Functions to do URL operations on strings.
-// These are operations that aren't faster on a parsed URL.
-
-bool protocolIs(const String& url, const char* protocol);
-
-String mimeTypeFromDataURL(const String& url);
-
-// Unescapes the given string using URL escaping rules, given an optional
-// encoding (defaulting to UTF-8 otherwise). DANGER: If the URL has "%00"
-// in it, the resulting string will have embedded null characters!
-String decodeURLEscapeSequences(const String&);
-String decodeURLEscapeSequences(const String&, const TextEncoding&);
-
-String encodeWithURLEscapeSequences(const String&);
-
-#endif // ifndef KURL_DECORATE_GLOBALS
-
-// Inlines.
-
-#ifdef USE_GOOGLE_URL_LIBRARY
-
-inline bool operator==(const KURL& a, const KURL& b)
-{
- return a.utf8String() == b.utf8String();
-}
-
-inline bool operator!=(const KURL& a, const KURL& b)
-{
- return a.utf8String() != b.utf8String();
-}
-
-#else
-
-inline bool operator==(const KURL& a, const KURL& b)
-{
- return a.string() == b.string();
-}
-
-#endif
-
-inline bool operator==(const KURL& a, const String& b)
-{
- return a.string() == b;
-}
-
-inline bool operator==(const String& a, const KURL& b)
-{
- return a == b.string();
-}
-
-#ifndef USE_GOOGLE_URL_LIBRARY
-
-inline bool operator!=(const KURL& a, const KURL& b)
-{
- return a.string() != b.string();
-}
-
-#endif
-
-inline bool operator!=(const KURL& a, const String& b)
-{
- return a.string() != b;
-}
-
-inline bool operator!=(const String& a, const KURL& b)
-{
- return a != b.string();
-}
-
-} // namespace WebCore
-
-namespace WTF {
-
- // KURLHash is the default hash for String
- template<typename T> struct DefaultHash;
- template<> struct DefaultHash<WebCore::KURL> {
- typedef WebCore::KURLHash Hash;
- };
-
-} // namespace WTF
-
-#endif // KURL_h
diff --git a/webkit/pending/NodeFilter.cpp b/webkit/pending/NodeFilter.cpp
deleted file mode 100644
index 7e0fb50..0000000
--- a/webkit/pending/NodeFilter.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "NodeFilter.h"
-
-#include "ExceptionContext.h"
-#include "Node.h"
-
-namespace WebCore {
-
-short NodeFilter::acceptNode(ExceptionContext* exec, Node* node) const
-{
- // cast to short silences "enumeral and non-enumeral types in return" warning
- return m_condition ? m_condition->acceptNode(exec, node) : static_cast<short>(FILTER_ACCEPT);
-}
-
-short NodeFilter::acceptNode(Node* node) const
-{
- ExceptionContext context(node);
- return acceptNode(&context, node);
-}
-
-} // namespace WebCore
diff --git a/webkit/pending/NodeFilter.h b/webkit/pending/NodeFilter.h
deleted file mode 100644
index ead7a0c..0000000
--- a/webkit/pending/NodeFilter.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef NodeFilter_h
-#define NodeFilter_h
-
-#include "NodeFilterCondition.h"
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefPtr.h>
-
-namespace WebCore {
-
- class ExceptionContext;
-
- class NodeFilter : public RefCounted<NodeFilter> {
- public:
- /**
- * The following constants are returned by the acceptNode()
- * method:
- */
- enum {
- FILTER_ACCEPT = 1,
- FILTER_REJECT = 2,
- FILTER_SKIP = 3
- };
-
- /**
- * These are the available values for the whatToShow parameter.
- * They are the same as the set of possible types for Node, and
- * their values are derived by using a bit position corresponding
- * to the value of NodeType for the equivalent node type.
- */
- enum {
- SHOW_ALL = 0xFFFFFFFF,
- SHOW_ELEMENT = 0x00000001,
- SHOW_ATTRIBUTE = 0x00000002,
- SHOW_TEXT = 0x00000004,
- SHOW_CDATA_SECTION = 0x00000008,
- SHOW_ENTITY_REFERENCE = 0x00000010,
- SHOW_ENTITY = 0x00000020,
- SHOW_PROCESSING_INSTRUCTION = 0x00000040,
- SHOW_COMMENT = 0x00000080,
- SHOW_DOCUMENT = 0x00000100,
- SHOW_DOCUMENT_TYPE = 0x00000200,
- SHOW_DOCUMENT_FRAGMENT = 0x00000400,
- SHOW_NOTATION = 0x00000800
- };
-
- static PassRefPtr<NodeFilter> create(PassRefPtr<NodeFilterCondition> condition)
- {
- return adoptRef(new NodeFilter(condition));
- }
-
- short acceptNode(ExceptionContext*, Node*) const;
- void mark() { m_condition->mark(); };
-
- // For non-JS bindings. Silently ignores the JavaScript exception if any.
- short acceptNode(Node* node) const;
-
- private:
- NodeFilter(PassRefPtr<NodeFilterCondition> condition) : m_condition(condition) { }
-
- RefPtr<NodeFilterCondition> m_condition;
- };
-
-} // namespace WebCore
-
-#endif // NodeFilter_h
diff --git a/webkit/pending/NodeFilterCondition.cpp b/webkit/pending/NodeFilterCondition.cpp
deleted file mode 100644
index e421492..0000000
--- a/webkit/pending/NodeFilterCondition.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "NodeFilterCondition.h"
-
-#include "NodeFilter.h"
-
-namespace WebCore {
-
-class ExceptionContext;
-
-short NodeFilterCondition::acceptNode(ExceptionContext*, Node*) const
-{
- return NodeFilter::FILTER_ACCEPT;
-}
-
-} // namespace WebCore
diff --git a/webkit/pending/NodeFilterCondition.h b/webkit/pending/NodeFilterCondition.h
deleted file mode 100644
index 4afdda6..0000000
--- a/webkit/pending/NodeFilterCondition.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef NodeFilterCondition_h
-#define NodeFilterCondition_h
-
-#include <wtf/RefCounted.h>
-
-namespace WebCore {
-
- class ExceptionContext;
- class Node;
-
- class NodeFilterCondition : public RefCounted<NodeFilterCondition> {
- public:
- virtual ~NodeFilterCondition() { }
- virtual short acceptNode(ExceptionContext*, Node*) const = 0;
- virtual void mark() { }
- };
-
-} // namespace WebCore
-
-#endif // NodeFilterCondition_h
diff --git a/webkit/pending/NodeIterator.cpp b/webkit/pending/NodeIterator.cpp
deleted file mode 100644
index ede32d0..0000000
--- a/webkit/pending/NodeIterator.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "NodeIterator.h"
-
-#include "Document.h"
-#include "ExceptionCode.h"
-#include "ExceptionContext.h"
-#include "NodeFilter.h"
-
-namespace WebCore {
-
-NodeIterator::NodePointer::NodePointer()
-{
-}
-
-NodeIterator::NodePointer::NodePointer(PassRefPtr<Node> n, bool b)
- : node(n)
- , isPointerBeforeNode(b)
-{
-}
-
-void NodeIterator::NodePointer::clear()
-{
- node.clear();
-}
-
-bool NodeIterator::NodePointer::moveToNext(Node* root)
-{
- if (!node)
- return false;
- if (isPointerBeforeNode) {
- isPointerBeforeNode = false;
- return true;
- }
- node = node->traverseNextNode(root);
- return node;
-}
-
-bool NodeIterator::NodePointer::moveToPrevious(Node* root)
-{
- if (!node)
- return false;
- if (!isPointerBeforeNode) {
- isPointerBeforeNode = true;
- return true;
- }
- node = node->traversePreviousNode(root);
- return node;
-}
-
-NodeIterator::NodeIterator(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
- : Traversal(rootNode, whatToShow, filter, expandEntityReferences)
- , m_referenceNode(root(), true)
- , m_detached(false)
-{
- root()->document()->attachNodeIterator(this);
-}
-
-NodeIterator::~NodeIterator()
-{
- root()->document()->detachNodeIterator(this);
-}
-
-PassRefPtr<Node> NodeIterator::nextNode(ExceptionContext* exec, ExceptionCode& ec)
-{
- if (m_detached) {
- ec = INVALID_STATE_ERR;
- return 0;
- }
-
- RefPtr<Node> result;
-
- m_candidateNode = m_referenceNode;
- while (m_candidateNode.moveToNext(root())) {
- // NodeIterators treat the DOM tree as a flat list of nodes.
- // In other words, FILTER_REJECT does not pass over descendants
- // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
- RefPtr<Node> provisionalResult = m_candidateNode.node;
- bool nodeWasAccepted = acceptNode(exec, provisionalResult.get()) == NodeFilter::FILTER_ACCEPT;
- if (exec && exec->hadException())
- break;
- if (nodeWasAccepted) {
- m_referenceNode = m_candidateNode;
- result = provisionalResult.release();
- break;
- }
- }
-
- m_candidateNode.clear();
- return result.release();
-}
-
-PassRefPtr<Node> NodeIterator::previousNode(ExceptionContext* exec, ExceptionCode& ec)
-{
- if (m_detached) {
- ec = INVALID_STATE_ERR;
- return 0;
- }
-
- RefPtr<Node> result;
-
- m_candidateNode = m_referenceNode;
- while (m_candidateNode.moveToPrevious(root())) {
- // NodeIterators treat the DOM tree as a flat list of nodes.
- // In other words, FILTER_REJECT does not pass over descendants
- // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
- RefPtr<Node> provisionalResult = m_candidateNode.node;
- bool nodeWasAccepted = acceptNode(exec, provisionalResult.get()) == NodeFilter::FILTER_ACCEPT;
- if (exec && exec->hadException())
- break;
- if (nodeWasAccepted) {
- m_referenceNode = m_candidateNode;
- result = provisionalResult.release();
- break;
- }
- }
-
- m_candidateNode.clear();
- return result.release();
-}
-
-void NodeIterator::detach()
-{
- root()->document()->detachNodeIterator(this);
- m_detached = true;
- m_referenceNode.node.clear();
-}
-
-void NodeIterator::nodeWillBeRemoved(Node* removedNode)
-{
- updateForNodeRemoval(removedNode, m_candidateNode);
- updateForNodeRemoval(removedNode, m_referenceNode);
-}
-
-void NodeIterator::updateForNodeRemoval(Node* removedNode, NodePointer& referenceNode) const
-{
- ASSERT(!m_detached);
- ASSERT(removedNode);
- ASSERT(root()->document() == removedNode->document());
-
- // Iterator is not affected if the removed node is the reference node and is the root.
- // or if removed node is not the reference node, or the ancestor of the reference node.
- if (!removedNode->isDescendantOf(root()))
- return;
- bool willRemoveReferenceNode = removedNode == referenceNode.node;
- bool willRemoveReferenceNodeAncestor = referenceNode.node && referenceNode.node->isDescendantOf(removedNode);
- if (!willRemoveReferenceNode && !willRemoveReferenceNodeAncestor)
- return;
-
- if (referenceNode.isPointerBeforeNode) {
- Node* node = removedNode->traverseNextNode(root());
- if (node) {
- // Move out from under the node being removed if the reference node is
- // a descendant of the node being removed.
- if (willRemoveReferenceNodeAncestor) {
- while (node && node->isDescendantOf(removedNode))
- node = node->traverseNextNode(root());
- }
- if (node)
- referenceNode.node = node;
- } else {
- node = removedNode->traversePreviousNode(root());
- if (node) {
- // Move out from under the node being removed if the reference node is
- // a descendant of the node being removed.
- if (willRemoveReferenceNodeAncestor) {
- while (node && node->isDescendantOf(removedNode))
- node = node->traversePreviousNode(root());
- }
- if (node) {
- // Removing last node.
- // Need to move the pointer after the node preceding the
- // new reference node.
- referenceNode.node = node;
- referenceNode.isPointerBeforeNode = false;
- }
- }
- }
- } else {
- Node* node = removedNode->traversePreviousNode(root());
- if (node) {
- // Move out from under the node being removed if the reference node is
- // a descendant of the node being removed.
- if (willRemoveReferenceNodeAncestor) {
- while (node && node->isDescendantOf(removedNode))
- node = node->traversePreviousNode(root());
- }
- if (node)
- referenceNode.node = node;
- } else {
- node = removedNode->traverseNextNode(root());
- // Move out from under the node being removed if the reference node is
- // a descendant of the node being removed.
- if (willRemoveReferenceNodeAncestor) {
- while (node && node->isDescendantOf(removedNode))
- node = node->traversePreviousNode(root());
- }
- if (node)
- referenceNode.node = node;
- }
- }
-}
-
-PassRefPtr<Node> NodeIterator::nextNode(ExceptionCode& ec)
-{
- ExceptionContext context(referenceNode());
- return nextNode(&context, ec);
-}
-
-PassRefPtr<Node> NodeIterator::previousNode(ExceptionCode& ec)
-{
- ExceptionContext context(referenceNode());
- return previousNode(&context, ec);
-}
-
-} // namespace WebCore
diff --git a/webkit/pending/NodeIterator.h b/webkit/pending/NodeIterator.h
deleted file mode 100644
index c53a010..0000000
--- a/webkit/pending/NodeIterator.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef NodeIterator_h
-#define NodeIterator_h
-
-#include "NodeFilter.h"
-#include "Traversal.h"
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-
-namespace WebCore {
-
- class ExceptionContext;
-
- typedef int ExceptionCode;
-
- class NodeIterator : public RefCounted<NodeIterator>, public Traversal {
- public:
- static PassRefPtr<NodeIterator> create(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
- {
- return adoptRef(new NodeIterator(rootNode, whatToShow, filter, expandEntityReferences));
- }
- ~NodeIterator();
-
- PassRefPtr<Node> nextNode(ExceptionContext*, ExceptionCode&);
- PassRefPtr<Node> previousNode(ExceptionContext*, ExceptionCode&);
- void detach();
-
- Node* referenceNode() const { return m_referenceNode.node.get(); }
- bool pointerBeforeReferenceNode() const { return m_referenceNode.isPointerBeforeNode; }
-
- // This function is called before any node is removed from the document tree.
- void nodeWillBeRemoved(Node*);
-
- // For non-JS bindings. Silently ignores the JavaScript exception if any.
- PassRefPtr<Node> nextNode(ExceptionCode& ec);
- PassRefPtr<Node> previousNode(ExceptionCode& ec);
-
- private:
- NodeIterator(PassRefPtr<Node>, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences);
-
- struct NodePointer {
- RefPtr<Node> node;
- bool isPointerBeforeNode;
- NodePointer();
- NodePointer(PassRefPtr<Node>, bool);
- void clear();
- bool moveToNext(Node* root);
- bool moveToPrevious(Node* root);
- };
-
- void updateForNodeRemoval(Node* nodeToBeRemoved, NodePointer&) const;
-
- NodePointer m_referenceNode;
- NodePointer m_candidateNode;
- bool m_detached;
- };
-
-} // namespace WebCore
-
-#endif // NodeIterator_h
diff --git a/webkit/pending/Page.cpp b/webkit/pending/Page.cpp
deleted file mode 100644
index abc89cf..0000000
--- a/webkit/pending/Page.cpp
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All Rights Reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "Page.h"
-
-#include "Chrome.h"
-#include "ChromeClient.h"
-#include "ContextMenuClient.h"
-#include "ContextMenuController.h"
-#include "CSSStyleSelector.h"
-#include "EditorClient.h"
-#include "DOMWindow.h"
-#include "DragController.h"
-#include "EventNames.h"
-#include "FileSystem.h"
-#include "FocusController.h"
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "FrameTree.h"
-#include "FrameView.h"
-#include "HistoryItem.h"
-#include "InspectorController.h"
-#include "JavaScriptDebugServer.h"
-#include "Logging.h"
-#include "NetworkStateNotifier.h"
-#include "PageGroup.h"
-#include "PluginData.h"
-#include "ProgressTracker.h"
-#include "RenderWidget.h"
-#include "SelectionController.h"
-#include "Settings.h"
-#include "StringHash.h"
-#include "TextResourceDecoder.h"
-#include "Widget.h"
-#include "ScriptController.h"
-#include <kjs/collector.h>
-#include <kjs/JSLock.h>
-#include <wtf/HashMap.h>
-#include <wtf/RefCountedLeakCounter.h>
-
-#if ENABLE(DOM_STORAGE)
-#include "LocalStorage.h"
-#include "SessionStorage.h"
-#include "StorageArea.h"
-#endif
-
-namespace WebCore {
-
-using namespace EventNames;
-
-static HashSet<Page*>* allPages;
-
-#ifndef NDEBUG
-static WTF::RefCountedLeakCounter pageCounter("Page");
-#endif
-
-static void networkStateChanged()
-{
- Vector<RefPtr<Frame> > frames;
-
- // Get all the frames of all the pages in all the page groups
- HashSet<Page*>::iterator end = allPages->end();
- for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
- for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
- frames.append(frame);
- }
-
- AtomicString eventName = networkStateNotifier().onLine() ? onlineEvent : offlineEvent;
-
- for (unsigned i = 0; i < frames.size(); i++) {
- Document* document = frames[i]->document();
-
- if (!document)
- continue;
-
- // If the document does not have a body the event should be dispatched to the document
- EventTargetNode* eventTarget = document->body();
- if (!eventTarget)
- eventTarget = document;
-
- eventTarget->dispatchHTMLEvent(eventName, false, false);
- }
-}
-
-Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, EditorClient* editorClient, DragClient* dragClient, InspectorClient* inspectorClient)
- : m_chrome(new Chrome(this, chromeClient))
- , m_dragCaretController(new SelectionController(0, true))
- , m_dragController(new DragController(this, dragClient))
- , m_focusController(new FocusController(this))
- , m_contextMenuController(new ContextMenuController(this, contextMenuClient))
- , m_inspectorController(new InspectorController(this, inspectorClient))
- , m_settings(new Settings(this))
- , m_progress(new ProgressTracker)
- , m_backForwardList(BackForwardList::create(this))
- , m_editorClient(editorClient)
- , m_frameCount(0)
- , m_tabKeyCyclesThroughElements(true)
- , m_defersLoading(false)
- , m_inLowQualityInterpolationMode(false)
- , m_parentInspectorController(0)
- , m_didLoadUserStyleSheet(false)
- , m_userStyleSheetModificationTime(0)
- , m_group(0)
- , m_debugger(0)
- , m_pendingUnloadEventCount(0)
- , m_pendingBeforeUnloadEventCount(0)
- , m_customHTMLTokenizerTimeDelay(-1)
- , m_customHTMLTokenizerChunkSize(-1)
-{
- if (!allPages) {
- allPages = new HashSet<Page*>;
- setFocusRingColorChangeFunction(setNeedsReapplyStyles);
-
- networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
- }
-
- ASSERT(!allPages->contains(this));
- allPages->add(this);
-
-#if USE(JSC)
- JavaScriptDebugServer::shared().pageCreated(this);
-#endif
-
-#ifndef NDEBUG
- pageCounter.increment();
-#endif
-}
-
-Page::~Page()
-{
- m_mainFrame->setView(0);
- setGroupName(String());
- allPages->remove(this);
-
- for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
- frame->pageDestroyed();
- m_editorClient->pageDestroyed();
- if (m_parentInspectorController)
- m_parentInspectorController->pageDestroyed();
- m_inspectorController->inspectedPageDestroyed();
-
- m_backForwardList->close();
-
-#ifndef NDEBUG
- pageCounter.decrement();
-
- // Cancel keepAlive timers, to ensure we release all Frames before exiting.
- // It's safe to do this because we prohibit closing a Page while JavaScript
- // is executing.
- Frame::cancelAllKeepAlive();
-#endif
-}
-
-void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
-{
- ASSERT(!m_mainFrame); // Should only be called during initialization
- m_mainFrame = mainFrame;
-}
-
-BackForwardList* Page::backForwardList()
-{
- return m_backForwardList.get();
-}
-
-bool Page::goBack()
-{
- HistoryItem* item = m_backForwardList->backItem();
-
- if (item) {
- goToItem(item, FrameLoadTypeBack);
- return true;
- }
- return false;
-}
-
-bool Page::goForward()
-{
- HistoryItem* item = m_backForwardList->forwardItem();
-
- if (item) {
- goToItem(item, FrameLoadTypeForward);
- return true;
- }
- return false;
-}
-
-void Page::goToItem(HistoryItem* item, FrameLoadType type)
-{
- // Abort any current load if we're going to a history item
- m_mainFrame->loader()->stopAllLoaders();
- m_mainFrame->loader()->goToItem(item, type);
-}
-
-void Page::setGroupName(const String& name)
-{
- if (m_group && !m_group->name().isEmpty()) {
- ASSERT(m_group != m_singlePageGroup.get());
- ASSERT(!m_singlePageGroup);
- m_group->removePage(this);
- }
-
- if (name.isEmpty())
- m_group = 0;
- else {
- m_singlePageGroup.clear();
- m_group = PageGroup::pageGroup(name);
- m_group->addPage(this);
- }
-}
-
-const String& Page::groupName() const
-{
- static String nullString;
- return m_group ? m_group->name() : nullString;
-}
-
-void Page::initGroup()
-{
- ASSERT(!m_singlePageGroup);
- ASSERT(!m_group);
- m_singlePageGroup.set(new PageGroup(this));
- m_group = m_singlePageGroup.get();
-}
-
-void Page::setNeedsReapplyStyles()
-{
- if (!allPages)
- return;
- HashSet<Page*>::iterator end = allPages->end();
- for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
- for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
- frame->setNeedsReapplyStyles();
-}
-
-void Page::refreshPlugins(bool reload)
-{
- if (!allPages)
- return;
-
- PluginData::refresh();
-
- Vector<RefPtr<Frame> > framesNeedingReload;
-
- HashSet<Page*>::iterator end = allPages->end();
- for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
- (*it)->m_pluginData = 0;
-
- if (reload) {
- for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
- if (frame->loader()->containsPlugins())
- framesNeedingReload.append(frame);
- }
- }
- }
-
- for (size_t i = 0; i < framesNeedingReload.size(); ++i)
- framesNeedingReload[i]->loader()->reload();
-}
-
-PluginData* Page::pluginData() const
-{
- if (!m_pluginData)
- m_pluginData = PluginData::create(this);
- return m_pluginData.get();
-}
-
-static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
-{
- return forward
- ? curr->tree()->traverseNextWithWrap(wrapFlag)
- : curr->tree()->traversePreviousWithWrap(wrapFlag);
-}
-
-bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap)
-{
- if (target.isEmpty() || !mainFrame())
- return false;
-
- Frame* frame = focusController()->focusedOrMainFrame();
- Frame* startFrame = frame;
- do {
- if (frame->findString(target, direction == FindDirectionForward, caseSensitivity == TextCaseSensitive, false, true)) {
- if (frame != startFrame)
- startFrame->selection()->clear();
- focusController()->setFocusedFrame(frame);
- return true;
- }
- frame = incrementFrame(frame, direction == FindDirectionForward, shouldWrap);
- } while (frame && frame != startFrame);
-
- // Search contents of startFrame, on the other side of the selection that we did earlier.
- // We cheat a bit and just research with wrap on
- if (shouldWrap && !startFrame->selection()->isNone()) {
- bool found = startFrame->findString(target, direction == FindDirectionForward, caseSensitivity == TextCaseSensitive, true, true);
- focusController()->setFocusedFrame(frame);
- return found;
- }
-
- return false;
-}
-
-unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
-{
- if (target.isEmpty() || !mainFrame())
- return 0;
-
- unsigned matches = 0;
-
- Frame* frame = mainFrame();
- do {
- frame->setMarkedTextMatchesAreHighlighted(shouldHighlight);
- matches += frame->markAllMatchesForText(target, caseSensitivity == TextCaseSensitive, (limit == 0) ? 0 : (limit - matches));
- frame = incrementFrame(frame, true, false);
- } while (frame);
-
- return matches;
-}
-
-void Page::unmarkAllTextMatches()
-{
- if (!mainFrame())
- return;
-
- Frame* frame = mainFrame();
- do {
- if (Document* document = frame->document())
- document->removeMarkers(DocumentMarker::TextMatch);
- frame = incrementFrame(frame, true, false);
- } while (frame);
-}
-
-const Selection& Page::selection() const
-{
- return focusController()->focusedOrMainFrame()->selection()->selection();
-}
-
-void Page::setDefersLoading(bool defers)
-{
- if (defers == m_defersLoading)
- return;
-
- m_defersLoading = defers;
- for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
- frame->loader()->setDefersLoading(defers);
-}
-
-void Page::clearUndoRedoOperations()
-{
- m_editorClient->clearUndoRedoOperations();
-}
-
-bool Page::inLowQualityImageInterpolationMode() const
-{
- return m_inLowQualityInterpolationMode;
-}
-
-void Page::setInLowQualityImageInterpolationMode(bool mode)
-{
- m_inLowQualityInterpolationMode = mode;
-}
-
-void Page::userStyleSheetLocationChanged()
-{
-#if !FRAME_LOADS_USER_STYLESHEET
- // FIXME: We should provide a way to load other types of URLs than just
- // file: (e.g., http:, data:).
- if (m_settings->userStyleSheetLocation().isLocalFile())
- m_userStyleSheetPath = m_settings->userStyleSheetLocation().fileSystemPath();
- else
- m_userStyleSheetPath = String();
-
- m_didLoadUserStyleSheet = false;
- m_userStyleSheet = String();
- m_userStyleSheetModificationTime = 0;
-#endif
-}
-
-const String& Page::userStyleSheet() const
-{
- if (m_userStyleSheetPath.isEmpty()) {
- ASSERT(m_userStyleSheet.isEmpty());
- return m_userStyleSheet;
- }
-
- time_t modTime;
- if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
- // The stylesheet either doesn't exist, was just deleted, or is
- // otherwise unreadable. If we've read the stylesheet before, we should
- // throw away that data now as it no longer represents what's on disk.
- m_userStyleSheet = String();
- return m_userStyleSheet;
- }
-
- // If the stylesheet hasn't changed since the last time we read it, we can
- // just return the old data.
- if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
- return m_userStyleSheet;
-
- m_didLoadUserStyleSheet = true;
- m_userStyleSheet = String();
- m_userStyleSheetModificationTime = modTime;
-
- // FIXME: It would be better to load this asynchronously to avoid blocking
- // the process, but we will first need to create an asynchronous loading
- // mechanism that is not tied to a particular Frame. We will also have to
- // determine what our behavior should be before the stylesheet is loaded
- // and what should happen when it finishes loading, especially with respect
- // to when the load event fires, when Document::close is called, and when
- // layout/paint are allowed to happen.
- RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
- if (!data)
- return m_userStyleSheet;
-
- m_userStyleSheet = TextResourceDecoder::create("text/css")->decode(data->data(), data->size());
-
- return m_userStyleSheet;
-}
-
-void Page::removeAllVisitedLinks()
-{
- if (!allPages)
- return;
- HashSet<PageGroup*> groups;
- HashSet<Page*>::iterator pagesEnd = allPages->end();
- for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
- if (PageGroup* group = (*it)->groupPtr())
- groups.add(group);
- }
- HashSet<PageGroup*>::iterator groupsEnd = groups.end();
- for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it)
- (*it)->removeVisitedLinks();
-}
-
-void Page::allVisitedStateChanged(PageGroup* group)
-{
- ASSERT(group);
- ASSERT(allPages);
- HashSet<Page*>::iterator pagesEnd = allPages->end();
- for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
- Page* page = *it;
- if (page->m_group != group)
- continue;
- for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
- if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
- styleSelector->allVisitedStateChanged();
- }
- }
-}
-
-void Page::visitedStateChanged(PageGroup* group, unsigned visitedLinkHash)
-{
- ASSERT(group);
- ASSERT(allPages);
- HashSet<Page*>::iterator pagesEnd = allPages->end();
- for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
- Page* page = *it;
- if (page->m_group != group)
- continue;
- for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
- if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
- styleSelector->visitedStateChanged(visitedLinkHash);
- }
- }
-}
-
-void Page::setDebuggerForAllPages(KJS::Debugger* debugger)
-{
- ASSERT(allPages);
-
- HashSet<Page*>::iterator end = allPages->end();
- for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
- (*it)->setDebugger(debugger);
-}
-
-void Page::setDebugger(KJS::Debugger* debugger)
-{
- if (m_debugger == debugger)
- return;
-
- m_debugger = debugger;
-
- for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext())
- frame->script()->attachDebugger(m_debugger);
-}
-
-#if ENABLE(DOM_STORAGE)
-SessionStorage* Page::sessionStorage(bool optionalCreate)
-{
- if (!m_sessionStorage && optionalCreate)
- m_sessionStorage = SessionStorage::create(this);
-
- return m_sessionStorage.get();
-}
-
-void Page::setSessionStorage(PassRefPtr<SessionStorage> newStorage)
-{
- ASSERT(newStorage->page() == this);
- m_sessionStorage = newStorage;
-}
-#endif
-
-unsigned Page::pendingUnloadEventCount()
-{
- return m_pendingUnloadEventCount;
-}
-
-void Page::changePendingUnloadEventCount(int delta)
-{
- if (!delta)
- return;
- ASSERT( (delta + (int)m_pendingUnloadEventCount) >= 0 );
-
- if (m_pendingUnloadEventCount == 0)
- m_chrome->disableSuddenTermination();
- else if ((m_pendingUnloadEventCount + delta) == 0)
- m_chrome->enableSuddenTermination();
-
- m_pendingUnloadEventCount += delta;
- return;
-}
-
-unsigned Page::pendingBeforeUnloadEventCount()
-{
- return m_pendingBeforeUnloadEventCount;
-}
-
-void Page::changePendingBeforeUnloadEventCount(int delta)
-{
- if (!delta)
- return;
- ASSERT( (delta + (int)m_pendingBeforeUnloadEventCount) >= 0 );
-
- if (m_pendingBeforeUnloadEventCount == 0)
- m_chrome->disableSuddenTermination();
- else if ((m_pendingBeforeUnloadEventCount + delta) == 0)
- m_chrome->enableSuddenTermination();
-
- m_pendingBeforeUnloadEventCount += delta;
- return;
-}
-
-void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay)
-{
- if (customHTMLTokenizerTimeDelay < 0) {
- m_customHTMLTokenizerTimeDelay = -1;
- return;
- }
- m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay;
-}
-
-void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize)
-{
- if (customHTMLTokenizerChunkSize < 0) {
- m_customHTMLTokenizerChunkSize = -1;
- return;
- }
- m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize;
-}
-
-} // namespace WebCore
diff --git a/webkit/pending/Page.h b/webkit/pending/Page.h
deleted file mode 100644
index d0e5ca1..0000000
--- a/webkit/pending/Page.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef Page_h
-#define Page_h
-
-#include "BackForwardList.h"
-#include "Chrome.h"
-#include "ContextMenuController.h"
-#include "FrameLoaderTypes.h"
-#include "PlatformString.h"
-#if PLATFORM(MAC)
-#include "SchedulePair.h"
-#endif
-#include <wtf/HashSet.h>
-#include <wtf/OwnPtr.h>
-
-#if PLATFORM(WIN) || (PLATFORM(WX) && PLATFORM(WIN_OS)) || (PLATFORM(QT) && defined(Q_WS_WIN))
-typedef struct HINSTANCE__* HINSTANCE;
-#endif
-
-namespace KJS {
- class Debugger;
-}
-
-namespace WebCore {
-
- class Chrome;
- class ChromeClient;
- class ContextMenuClient;
- class ContextMenuController;
- class Document;
- class DragClient;
- class DragController;
- class EditorClient;
- class FocusController;
- class Frame;
- class InspectorClient;
- class InspectorController;
- class Node;
- class PageGroup;
- class PluginData;
- class ProgressTracker;
- class Selection;
- class SelectionController;
-#if ENABLE(DOM_STORAGE)
- class SessionStorage;
-#endif
- class Settings;
- class KURL;
-
- enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive };
- enum FindDirection { FindDirectionForward, FindDirectionBackward };
-
- class Page : Noncopyable {
- public:
- static void setNeedsReapplyStyles();
-
- Page(ChromeClient*, ContextMenuClient*, EditorClient*, DragClient*, InspectorClient*);
- ~Page();
-
- static void refreshPlugins(bool reload);
- PluginData* pluginData() const;
-
- EditorClient* editorClient() const { return m_editorClient; }
-
- void setMainFrame(PassRefPtr<Frame>);
- Frame* mainFrame() const { return m_mainFrame.get(); }
-
- BackForwardList* backForwardList();
-
- // FIXME: The following three methods don't fall under the responsibilities of the Page object
- // They seem to fit a hypothetical Page-controller object that would be akin to the
- // Frame-FrameLoader relationship. They have to live here now, but should move somewhere that
- // makes more sense when that class exists.
- bool goBack();
- bool goForward();
- void goToItem(HistoryItem*, FrameLoadType);
-
- void setGroupName(const String&);
- const String& groupName() const;
-
- PageGroup& group() { if (!m_group) initGroup(); return *m_group; }
- PageGroup* groupPtr() { return m_group; } // can return 0
-
- void incrementFrameCount() { ++m_frameCount; }
- void decrementFrameCount() { --m_frameCount; }
- int frameCount() const { return m_frameCount; }
-
- Chrome* chrome() const { return m_chrome.get(); }
- SelectionController* dragCaretController() const { return m_dragCaretController.get(); }
- DragController* dragController() const { return m_dragController.get(); }
- FocusController* focusController() const { return m_focusController.get(); }
- ContextMenuController* contextMenuController() const { return m_contextMenuController.get(); }
- InspectorController* inspectorController() const { return m_inspectorController.get(); }
- Settings* settings() const { return m_settings.get(); }
- ProgressTracker* progress() const { return m_progress.get(); }
-
- void setParentInspectorController(InspectorController* controller) { m_parentInspectorController = controller; }
- InspectorController* parentInspectorController() const { return m_parentInspectorController; }
-
- void setTabKeyCyclesThroughElements(bool b) { m_tabKeyCyclesThroughElements = b; }
- bool tabKeyCyclesThroughElements() const { return m_tabKeyCyclesThroughElements; }
-
- bool findString(const String&, TextCaseSensitivity, FindDirection, bool shouldWrap);
- unsigned int markAllMatchesForText(const String&, TextCaseSensitivity, bool shouldHighlight, unsigned);
- void unmarkAllTextMatches();
-
-#if PLATFORM(MAC)
- void addSchedulePair(PassRefPtr<SchedulePair>);
- void removeSchedulePair(PassRefPtr<SchedulePair>);
- SchedulePairHashSet* scheduledRunLoopPairs() { return m_scheduledRunLoopPairs.get(); }
-
- OwnPtr<SchedulePairHashSet> m_scheduledRunLoopPairs;
-#endif
-
- const Selection& selection() const;
-
- void setDefersLoading(bool);
- bool defersLoading() const { return m_defersLoading; }
-
- void clearUndoRedoOperations();
-
- bool inLowQualityImageInterpolationMode() const;
- void setInLowQualityImageInterpolationMode(bool = true);
-
- void userStyleSheetLocationChanged();
- const String& userStyleSheet() const;
-
- void changePendingUnloadEventCount(int delta);
- unsigned pendingUnloadEventCount();
- void changePendingBeforeUnloadEventCount(int delta);
- unsigned pendingBeforeUnloadEventCount();
-
- static void setDebuggerForAllPages(KJS::Debugger*);
- void setDebugger(KJS::Debugger*);
- KJS::Debugger* debugger() const { return m_debugger; }
-
-#if PLATFORM(WIN) || (PLATFORM(WX) && PLATFORM(WIN_OS)) || (PLATFORM(QT) && defined(Q_WS_WIN))
- // The global DLL or application instance used for all windows.
- static void setInstanceHandle(HINSTANCE instanceHandle) { s_instanceHandle = instanceHandle; }
- static HINSTANCE instanceHandle() { return s_instanceHandle; }
-#endif
-
- static void removeAllVisitedLinks();
-
- static void allVisitedStateChanged(PageGroup*);
- static void visitedStateChanged(PageGroup*, unsigned visitedHash);
-
-#if ENABLE(DOM_STORAGE)
- SessionStorage* sessionStorage(bool optionalCreate = true);
- void setSessionStorage(PassRefPtr<SessionStorage>);
-#endif
-
- void setCustomHTMLTokenizerTimeDelay(double);
- bool hasCustomHTMLTokenizerTimeDelay() const { return m_customHTMLTokenizerTimeDelay != -1; }
- double customHTMLTokenizerTimeDelay() const { ASSERT(m_customHTMLTokenizerTimeDelay != -1); return m_customHTMLTokenizerTimeDelay; }
-
- void setCustomHTMLTokenizerChunkSize(int);
- bool hasCustomHTMLTokenizerChunkSize() const { return m_customHTMLTokenizerChunkSize != -1; }
- int customHTMLTokenizerChunkSize() const { ASSERT(m_customHTMLTokenizerChunkSize != -1); return m_customHTMLTokenizerChunkSize; }
-
- private:
- void initGroup();
-
- OwnPtr<Chrome> m_chrome;
- OwnPtr<SelectionController> m_dragCaretController;
- OwnPtr<DragController> m_dragController;
- OwnPtr<FocusController> m_focusController;
- OwnPtr<ContextMenuController> m_contextMenuController;
- OwnPtr<Settings> m_settings;
- OwnPtr<ProgressTracker> m_progress;
-
-#if USE(V8)
- // To fix crash in inspector window (Bug 904340)
- RefPtr<InspectorController> m_inspectorController;
-#else
- OwnPtr<InspectorController> m_inspectorController;
-#endif
- RefPtr<BackForwardList> m_backForwardList;
- RefPtr<Frame> m_mainFrame;
-
- mutable RefPtr<PluginData> m_pluginData;
-
- EditorClient* m_editorClient;
-
- int m_frameCount;
- String m_groupName;
-
- bool m_tabKeyCyclesThroughElements;
- bool m_defersLoading;
-
- bool m_inLowQualityInterpolationMode;
-
- InspectorController* m_parentInspectorController;
-
- String m_userStyleSheetPath;
- mutable String m_userStyleSheet;
- mutable bool m_didLoadUserStyleSheet;
- mutable time_t m_userStyleSheetModificationTime;
-
- OwnPtr<PageGroup> m_singlePageGroup;
- PageGroup* m_group;
-
- KJS::Debugger* m_debugger;
-
- unsigned m_pendingUnloadEventCount;
- unsigned m_pendingBeforeUnloadEventCount;
-
- double m_customHTMLTokenizerTimeDelay;
- int m_customHTMLTokenizerChunkSize;
-
-#if ENABLE(DOM_STORAGE)
- RefPtr<SessionStorage> m_sessionStorage;
-#endif
-#if PLATFORM(WIN) || (PLATFORM(WX) && defined(__WXMSW__)) || (PLATFORM(QT) && defined(Q_WS_WIN))
- static HINSTANCE s_instanceHandle;
-#endif
- };
-
-} // namespace WebCore
-
-#endif // Page_h
diff --git a/webkit/pending/RenderButton.cpp b/webkit/pending/RenderButton.cpp
deleted file mode 100644
index 34d30f0..0000000
--- a/webkit/pending/RenderButton.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * This file is part of the html renderer for KDE.
- *
- * Copyright (C) 2005 Apple Computer, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "RenderButton.h"
-
-#include "Document.h"
-#include "GraphicsContext.h"
-#include "HTMLInputElement.h"
-#include "HTMLNames.h"
-#include "RenderTextFragment.h"
-#include "RenderTheme.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-RenderButton::RenderButton(Node* node)
- : RenderFlexibleBox(node)
- , m_buttonText(0)
- , m_inner(0)
- , m_default(false)
-{
-}
-
-void RenderButton::addChild(RenderObject* newChild, RenderObject* beforeChild)
-{
- if (!m_inner) {
- // Create an anonymous block.
- ASSERT(!firstChild());
- m_inner = createAnonymousBlock();
- setupInnerStyle(m_inner->style());
- RenderFlexibleBox::addChild(m_inner);
- }
-
- m_inner->addChild(newChild, beforeChild);
-}
-
-void RenderButton::removeChild(RenderObject* oldChild)
-{
- if (oldChild == m_inner || !m_inner) {
- RenderFlexibleBox::removeChild(oldChild);
- m_inner = 0;
- } else
- m_inner->removeChild(oldChild);
-}
-
-void RenderButton::setStyle(RenderStyle* style)
-{
- RenderBlock::setStyle(style);
- if (m_buttonText)
- m_buttonText->setStyle(style);
- if (m_inner) {
- // RenderBlock handled updating the anonymous block's style.
- setupInnerStyle(m_inner->style());
- }
- setReplaced(isInline());
-
- if (!m_default && theme()->isDefault(this)) {
- if (!m_timer)
- m_timer.set(new Timer<RenderButton>(this, &RenderButton::timerFired));
- m_timer->startRepeating(0.01);
- m_default = true;
- } else if (m_default && !theme()->isDefault(this)) {
- m_default = false;
- m_timer.clear();
- }
-}
-
-void RenderButton::setupInnerStyle(RenderStyle* style) {
- ASSERT(style->refCount() == 1);
- // RenderBlock::createAnonymousBlock creates a new RenderStyle, so this is
- // safe to modify.
- style->setBoxFlex(1.0f);
- theme()->adjustButtonInnerStyle(style);
-}
-
-void RenderButton::updateFromElement()
-{
- // If we're an input element, we may need to change our button text.
- if (element()->hasTagName(inputTag)) {
- HTMLInputElement* input = static_cast<HTMLInputElement*>(element());
- String value = input->valueWithDefault();
- setText(value);
- }
-}
-
-bool RenderButton::canHaveChildren() const
-{
- // Input elements can't have children, but button elements can. We'll
- // write the code assuming any other button types that might emerge in the future
- // can also have children.
- return !element()->hasTagName(inputTag);
-}
-
-void RenderButton::setText(const String& str)
-{
- if (str.isEmpty()) {
- if (m_buttonText) {
- m_buttonText->destroy();
- m_buttonText = 0;
- }
- } else {
- if (m_buttonText)
- m_buttonText->setText(str.impl());
- else {
- m_buttonText = new (renderArena()) RenderTextFragment(document(), str.impl());
- m_buttonText->setStyle(style());
- addChild(m_buttonText);
- }
- }
-}
-
-void RenderButton::updateBeforeAfterContent(RenderStyle::PseudoId type)
-{
- if (m_inner)
- m_inner->updateBeforeAfterContentForContainer(type, this);
- else
- updateBeforeAfterContentForContainer(type, this);
-}
-
-IntRect RenderButton::controlClipRect(int tx, int ty) const
-{
- // Clip to the padding box to at least give content the extra padding space.
- return IntRect(tx + borderLeft(), ty + borderTop(), m_width - borderLeft() - borderRight(), m_height - borderTop() - borderBottom());
-}
-
-void RenderButton::timerFired(Timer<RenderButton>*)
-{
- repaint();
-}
-
-} // namespace WebCore
diff --git a/webkit/pending/RenderButton.h b/webkit/pending/RenderButton.h
deleted file mode 100644
index 27a6827..0000000
--- a/webkit/pending/RenderButton.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * This file is part of the html renderer for KDE.
- *
- * Copyright (C) 2005 Apple Computer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef RenderButton_h
-#define RenderButton_h
-
-#include "RenderFlexibleBox.h"
-#include "Timer.h"
-#include <wtf/OwnPtr.h>
-
-namespace WebCore {
-
-class RenderTextFragment;
-
-// RenderButtons are just like normal flexboxes except that they will generate an anonymous block child.
-// For inputs, they will also generate an anonymous RenderText and keep its style and content up
-// to date as the button changes.
-class RenderButton : public RenderFlexibleBox {
-public:
- RenderButton(Node*);
-
- virtual const char* renderName() const { return "RenderButton"; }
-
- virtual void addChild(RenderObject* newChild, RenderObject *beforeChild = 0);
- virtual void removeChild(RenderObject*);
- virtual void removeLeftoverAnonymousBlock(RenderBlock*) { }
- virtual bool createsAnonymousWrapper() const { return true; }
-
- virtual void setStyle(RenderStyle*);
- void setupInnerStyle(RenderStyle*);
- virtual void updateFromElement();
-
- virtual void updateBeforeAfterContent(RenderStyle::PseudoId);
-
- virtual bool hasControlClip() const { return true; }
- virtual IntRect controlClipRect(int /*tx*/, int /*ty*/) const;
-
- void setText(const String&);
-
- virtual bool canHaveChildren() const;
-
-protected:
- virtual bool hasLineIfEmpty() const { return true; }
-
- void timerFired(Timer<RenderButton>*);
-
- RenderTextFragment* m_buttonText;
- RenderBlock* m_inner;
-
- OwnPtr<Timer<RenderButton> > m_timer;
- bool m_default;
-};
-
-} // namespace WebCore
-
-#endif // RenderButton_h
diff --git a/webkit/pending/RenderPartObject.cpp b/webkit/pending/RenderPartObject.cpp
deleted file mode 100644
index 86ea516..0000000
--- a/webkit/pending/RenderPartObject.cpp
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * (C) 2000 Simon Hausmann <hausmann@kde.org>
- * (C) 2000 Stefan Schimanski (1Stein@gmx.de)
- * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "RenderPartObject.h"
-
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "FrameLoaderClient.h"
-#include "FrameTree.h"
-#include "FrameView.h"
-#include "HTMLEmbedElement.h"
-#include "HTMLIFrameElement.h"
-#include "HTMLNames.h"
-#include "HTMLObjectElement.h"
-#include "HTMLParamElement.h"
-#include "MIMETypeRegistry.h"
-#include "Page.h"
-#include "Text.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-RenderPartObject::RenderPartObject(HTMLFrameOwnerElement* element)
- : RenderPart(element)
-{
- // init RenderObject attributes
- setInline(true);
- m_hasFallbackContent = false;
-}
-
-RenderPartObject::~RenderPartObject()
-{
- if (m_view)
- m_view->removeWidgetToUpdate(this);
-}
-
-static bool isURLAllowed(Document* doc, const String& url)
-{
- if (doc->frame()->page()->frameCount() >= 200)
- return false;
-
- // We allow one level of self-reference because some sites depend on that.
- // But we don't allow more than one.
- KURL completeURL = doc->completeURL(url);
- bool foundSelfReference = false;
- for (Frame* frame = doc->frame(); frame; frame = frame->tree()->parent()) {
- if (equalIgnoringRef(frame->loader()->url(), completeURL)) {
- if (foundSelfReference)
- return false;
- foundSelfReference = true;
- }
- }
- return true;
-}
-
-static inline void mapClassIdToServiceType(const String& classId, String& serviceType)
-{
- // It is ActiveX, but the nsplugin system handling
- // should also work, that's why we don't override the
- // serviceType with application/x-oleobject
- // but let the KTrader in khtmlpart::createPart() detect
- // the user's preference: launch with activex viewer or
- // with nspluginviewer (Niko)
-#ifndef DISABLE_ACTIVEX_TYPE_CONVERSION_FLASH
- if (classId.contains("D27CDB6E-AE6D-11cf-96B8-444553540000", false)) {
- serviceType = "application/x-shockwave-flash";
- return;
- }
-#endif
-#ifndef DISABLE_ACTIVEX_TYPE_CONVERSION_REALAUDIO
- if (classId.contains("CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA", false)) {
- serviceType = "audio/x-pn-realaudio-plugin";
- return;
- }
-#endif
-#ifndef DISABLE_ACTIVEX_TYPE_CONVERSION_QUICKTIME
- if (classId.contains("02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", false)) {
- serviceType = "video/quicktime";
- return;
- }
-#endif
-#ifndef DISABLE_ACTIVEX_TYPE_CONVERSION_DIRECTOR
- if (classId.contains("166B1BCA-3F9C-11CF-8075-444553540000", false)) {
- serviceType = "application/x-director";
- return;
- }
-#endif
-#ifndef DISABLE_ACTIVEX_TYPE_CONVERSION_MPLAYER2
- if (classId.contains("6BF52A52-394A-11d3-B153-00C04F79FAA6", false)) {
- serviceType = "application/x-mplayer2";
- return;
- }
-#endif
- // TODO: add more plugins here
-
- if (!classId.isEmpty()) {
- // We have a clsid, means this is activex (Niko)
- serviceType = "application/x-oleobject";
- }
-}
-
-// By default, when an Object element contains an embed tag, we will try to
-// create a plugin for the embed tag. However we will not do this for Windows
-// media object because our internal ActiveX plugin supports scripting and
-// some websites rely on that. The default npdsplay.dll plugin doesn't support
-// scripting.
-static bool ShouldUseEmbedForObject(HTMLObjectElement* o)
-{
-#ifndef DISABLE_ACTIVEX_TYPE_CONVERSION_MPLAYER2
- return true;
-#endif
- NamedAttrMap* attributes = o->attributes();
- if (attributes) {
- for (unsigned i = 0; i < attributes->length(); ++i) {
- Attribute* it = attributes->attributeItem(i);
- if (it->name().localName().string().foldCase() == "classid") {
- // If it's windows media player type.
- if (it->value().contains("6BF52A52-394A-11d3-B153-00C04F79FAA6", false) ||
- it->value().contains("22D6F312-B0F6-11D0-94AB-0080C74C7E95", false))
- return false;
- }
- }
- }
- return true;
-}
-
-void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins)
-{
- String url;
- String serviceType;
- Vector<String> paramNames;
- Vector<String> paramValues;
- Frame* frame = m_view->frame();
-
- if (element()->hasTagName(objectTag)) {
-
- HTMLObjectElement* o = static_cast<HTMLObjectElement*>(element());
-
- o->setNeedWidgetUpdate(false);
- if (!o->isFinishedParsingChildren())
- return;
- // Check for a child EMBED tag.
- HTMLEmbedElement* embed = 0;
- if (ShouldUseEmbedForObject(o)) {
- for (Node* child = o->firstChild(); child;) {
- if (child->hasTagName(embedTag)) {
- embed = static_cast<HTMLEmbedElement*>(child);
- break;
- } else if (child->hasTagName(objectTag))
- child = child->nextSibling(); // Don't descend into nested OBJECT tags
- else
- child = child->traverseNextNode(o); // Otherwise descend (EMBEDs may be inside COMMENT tags)
- }
- }
- // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT.
- HTMLElement *embedOrObject;
- if (embed) {
- embedOrObject = (HTMLElement *)embed;
- url = embed->url();
- serviceType = embed->serviceType();
- } else
- embedOrObject = (HTMLElement *)o;
-
- // If there was no URL or type defined in EMBED, try the OBJECT tag.
- if (url.isEmpty())
- url = o->url();
- if (serviceType.isEmpty())
- serviceType = o->serviceType();
-
- HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
-
- // Scan the PARAM children.
- // Get the URL and type from the params if we don't already have them.
- // Get the attributes from the params if there is no EMBED tag.
- Node *child = o->firstChild();
- while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) {
- if (child->hasTagName(paramTag)) {
- HTMLParamElement* p = static_cast<HTMLParamElement*>(child);
- String name = p->name();
- if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url")))
- url = p->value();
- if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) {
- serviceType = p->value();
- int pos = serviceType.find(";");
- if (pos != -1)
- serviceType = serviceType.left(pos);
- }
- if (!embed && !name.isEmpty()) {
- uniqueParamNames.add(name.impl());
- paramNames.append(p->name());
- paramValues.append(p->value());
- }
- }
- child = child->nextSibling();
- }
-
- // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
- // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
- // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
- // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
- // else our Java plugin will misinterpret it. [4004531]
- String codebase;
- if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
- codebase = "codebase";
- uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
- }
-
- // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values.
- NamedAttrMap* attributes = embedOrObject->attributes();
- if (attributes) {
- for (unsigned i = 0; i < attributes->length(); ++i) {
- Attribute* it = attributes->attributeItem(i);
- const AtomicString& name = it->name().localName();
- if (embed || !uniqueParamNames.contains(name.impl())) {
- paramNames.append(name.string());
- paramValues.append(it->value().string());
- }
- }
- }
-
- // If we still don't have a type, try to map from a specific CLASSID to a type.
- // However, if we have the embed tag we shouldn't do so because the outer object
- // may be converted to application/x-oleobject, while we are not getting the paramaters
- // including classid etc for the outer object.
- if (serviceType.isEmpty() && !o->classId().isEmpty() && !embed)
- mapClassIdToServiceType(o->classId(), serviceType);
-
- if (!isURLAllowed(document(), url))
- return;
-
- // Find out if we support fallback content.
- m_hasFallbackContent = false;
- for (Node *child = o->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) {
- if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag)) || // Discount <embed> and <param>
- (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace()))
- m_hasFallbackContent = true;
- }
-
- if (onlyCreateNonNetscapePlugins) {
- KURL completedURL;
- if (!url.isEmpty())
- completedURL = frame->loader()->completeURL(url);
-
- if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
- return;
- }
-
- bool success = frame->loader()->requestObject(this, url, AtomicString(o->name()), serviceType, paramNames, paramValues);
- if (!success && m_hasFallbackContent)
- o->renderFallbackContent();
- } else if (element()->hasTagName(embedTag)) {
- HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(element());
- o->setNeedWidgetUpdate(false);
- url = o->url();
- serviceType = o->serviceType();
-
- if (url.isEmpty() && serviceType.isEmpty())
- return;
- if (!isURLAllowed(document(), url))
- return;
-
- // add all attributes set on the embed object
- NamedAttrMap* a = o->attributes();
- if (a) {
- for (unsigned i = 0; i < a->length(); ++i) {
- Attribute* it = a->attributeItem(i);
- paramNames.append(it->name().localName().string());
- paramValues.append(it->value().string());
- }
- }
-
- if (onlyCreateNonNetscapePlugins) {
- KURL completedURL;
- if (!url.isEmpty())
- completedURL = frame->loader()->completeURL(url);
-
- if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
- return;
-
- }
-
- frame->loader()->requestObject(this, url, o->getAttribute(nameAttr), serviceType, paramNames, paramValues);
- }
-}
-
-void RenderPartObject::layout()
-{
- ASSERT(needsLayout());
-
- calcWidth();
- calcHeight();
- adjustOverflowForBoxShadow();
-
- RenderPart::layout();
-
- if (!m_widget && m_view)
- m_view->addWidgetToUpdate(this);
-
- setNeedsLayout(false);
-}
-
-void RenderPartObject::viewCleared()
-{
- if (element() && m_widget && m_widget->isFrameView()) {
- FrameView* view = static_cast<FrameView*>(m_widget);
- int marginw = -1;
- int marginh = -1;
- if (element()->hasTagName(iframeTag)) {
- HTMLIFrameElement* frame = static_cast<HTMLIFrameElement*>(element());
- marginw = frame->getMarginWidth();
- marginh = frame->getMarginHeight();
- }
- if (marginw != -1)
- view->setMarginWidth(marginw);
- if (marginh != -1)
- view->setMarginHeight(marginh);
- }
-}
-
-}
diff --git a/webkit/pending/RenderText.cpp b/webkit/pending/RenderText.cpp
deleted file mode 100644
index c01e1fc..0000000
--- a/webkit/pending/RenderText.cpp
+++ /dev/null
@@ -1,1176 +0,0 @@
-/**
- * (C) 1999 Lars Knoll (knoll@kde.org)
- * (C) 2000 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
- * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
- * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "RenderText.h"
-
-#include "CharacterNames.h"
-#include "InlineTextBox.h"
-#include "Range.h"
-#include "RenderArena.h"
-#include "RenderBlock.h"
-#include "RenderLayer.h"
-#include "Text.h"
-#include "TextBreakIterator.h"
-#include "break_lines.h"
-#include <wtf/AlwaysInline.h>
-
-using namespace std;
-using namespace WTF;
-using namespace Unicode;
-
-namespace WebCore {
-
-// FIXME: Move to StringImpl.h eventually.
-static inline bool charactersAreAllASCII(StringImpl* text)
-{
- return charactersAreAllASCII(text->characters(), text->length());
-}
-
-RenderText::RenderText(Node* node, PassRefPtr<StringImpl> str)
- : RenderObject(node)
- , m_text(str)
- , m_firstTextBox(0)
- , m_lastTextBox(0)
- , m_minWidth(-1)
- , m_maxWidth(-1)
- , m_selectionState(SelectionNone)
- , m_hasTab(false)
- , m_linesDirty(false)
- , m_containsReversedText(false)
- , m_isAllASCII(charactersAreAllASCII(m_text.get()))
-{
- ASSERT(m_text);
- setRenderText();
- m_text = m_text->replace('\\', backslashAsCurrencySymbol());
-}
-
-#ifndef NDEBUG
-
-RenderText::~RenderText()
-{
- ASSERT(!m_firstTextBox);
- ASSERT(!m_lastTextBox);
-}
-
-#endif
-
-const char* RenderText::renderName() const
-{
- return "RenderText";
-}
-
-bool RenderText::isTextFragment() const
-{
- return false;
-}
-
-bool RenderText::isWordBreak() const
-{
- return false;
-}
-
-void RenderText::setStyle(RenderStyle* newStyle)
-{
- RenderStyle* oldStyle = style();
- if (oldStyle == newStyle)
- return;
-
- ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
- ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;
-
- RenderObject::setStyle(newStyle);
-
- if (oldTransform != newStyle->textTransform() || oldSecurity != newStyle->textSecurity()
-#if ENABLE(SVG)
- || isSVGText() /* All SVG text has to be transformed */
-#endif
- ) {
- if (RefPtr<StringImpl> textToTransform = originalText())
- setText(textToTransform.release(), true);
- }
-}
-
-void RenderText::destroy()
-{
- if (!documentBeingDestroyed()) {
- if (firstTextBox()) {
- if (isBR()) {
- RootInlineBox* next = firstTextBox()->root()->nextRootBox();
- if (next)
- next->markDirty();
- }
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- box->remove();
- } else if (parent())
- parent()->dirtyLinesFromChangedChild(this);
- }
- deleteTextBoxes();
- RenderObject::destroy();
-}
-
-void RenderText::extractTextBox(InlineTextBox* box)
-{
- checkConsistency();
-
- m_lastTextBox = box->prevTextBox();
- if (box == m_firstTextBox)
- m_firstTextBox = 0;
- if (box->prevTextBox())
- box->prevTextBox()->setNextLineBox(0);
- box->setPreviousLineBox(0);
- for (InlineRunBox* curr = box; curr; curr = curr->nextLineBox())
- curr->setExtracted();
-
- checkConsistency();
-}
-
-void RenderText::attachTextBox(InlineTextBox* box)
-{
- checkConsistency();
-
- if (m_lastTextBox) {
- m_lastTextBox->setNextLineBox(box);
- box->setPreviousLineBox(m_lastTextBox);
- } else
- m_firstTextBox = box;
- InlineTextBox* last = box;
- for (InlineTextBox* curr = box; curr; curr = curr->nextTextBox()) {
- curr->setExtracted(false);
- last = curr;
- }
- m_lastTextBox = last;
-
- checkConsistency();
-}
-
-void RenderText::removeTextBox(InlineTextBox* box)
-{
- checkConsistency();
-
- if (box == m_firstTextBox)
- m_firstTextBox = box->nextTextBox();
- if (box == m_lastTextBox)
- m_lastTextBox = box->prevTextBox();
- if (box->nextTextBox())
- box->nextTextBox()->setPreviousLineBox(box->prevTextBox());
- if (box->prevTextBox())
- box->prevTextBox()->setNextLineBox(box->nextTextBox());
-
- checkConsistency();
-}
-
-void RenderText::deleteTextBoxes()
-{
- if (firstTextBox()) {
- RenderArena* arena = renderArena();
- InlineTextBox* next;
- for (InlineTextBox* curr = firstTextBox(); curr; curr = next) {
- next = curr->nextTextBox();
- curr->destroy(arena);
- }
- m_firstTextBox = m_lastTextBox = 0;
- }
-}
-
-PassRefPtr<StringImpl> RenderText::originalText() const
-{
- Node* e = element();
- return e ? static_cast<Text*>(e)->string() : 0;
-}
-
-void RenderText::absoluteRects(Vector<IntRect>& rects, int tx, int ty, bool)
-{
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- rects.append(IntRect(tx + box->xPos(), ty + box->yPos(), box->width(), box->height()));
-}
-
-void RenderText::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigned end, bool useSelectionHeight)
-{
- // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
- // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
- // function to take ints causes various internal mismatches. But selectionRect takes ints, and
- // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
- // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
- ASSERT(end == UINT_MAX || end <= INT_MAX);
- ASSERT(start <= INT_MAX);
- start = min(start, static_cast<unsigned>(INT_MAX));
- end = min(end, static_cast<unsigned>(INT_MAX));
-
- int x, y;
- absolutePositionForContent(x, y);
-
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
- // Note: box->end() returns the index of the last character, not the index past it
- if (start <= box->start() && box->end() < end) {
- IntRect r = IntRect(x + box->xPos(), y + box->yPos(), box->width(), box->height());
- if (useSelectionHeight) {
- IntRect selectionRect = box->selectionRect(x, y, start, end);
- r.setHeight(selectionRect.height());
- r.setY(selectionRect.y());
- }
- rects.append(r);
- } else {
- unsigned realEnd = min(box->end() + 1, end);
- IntRect r = box->selectionRect(x, y, start, realEnd);
- if (!r.isEmpty()) {
- if (!useSelectionHeight) {
- // change the height and y position because selectionRect uses selection-specific values
- r.setHeight(box->height());
- r.setY(y + box->yPos());
- }
- rects.append(r);
- }
- }
- }
-}
-
-InlineTextBox* RenderText::findNextInlineTextBox(int offset, int& pos) const
-{
- // The text runs point to parts of the RenderText's m_text
- // (they don't include '\n')
- // Find the text run that includes the character at offset
- // and return pos, which is the position of the char in the run.
-
- if (!m_firstTextBox)
- return 0;
-
- InlineTextBox* s = m_firstTextBox;
- int off = s->m_len;
- while (offset > off && s->nextTextBox()) {
- s = s->nextTextBox();
- off = s->m_start + s->m_len;
- }
- // we are now in the correct text run
- pos = (offset > off ? s->m_len : s->m_len - (off - offset) );
- return s;
-}
-
-VisiblePosition RenderText::positionForCoordinates(int x, int y)
-{
- if (!firstTextBox() || textLength() == 0)
- return VisiblePosition(element(), 0, DOWNSTREAM);
-
- // Get the offset for the position, since this will take rtl text into account.
- int offset;
-
- // FIXME: We should be able to roll these special cases into the general cases in the loop below.
- if (firstTextBox() && y < firstTextBox()->root()->bottomOverflow() && x < firstTextBox()->m_x) {
- // at the y coordinate of the first line or above
- // and the x coordinate is to the left of the first text box left edge
- offset = firstTextBox()->offsetForPosition(x);
- return VisiblePosition(element(), offset + firstTextBox()->m_start, DOWNSTREAM);
- }
- if (lastTextBox() && y >= lastTextBox()->root()->topOverflow() && x >= lastTextBox()->m_x + lastTextBox()->m_width) {
- // at the y coordinate of the last line or below
- // and the x coordinate is to the right of the last text box right edge
- offset = lastTextBox()->offsetForPosition(x);
- return VisiblePosition(element(), offset + lastTextBox()->m_start, DOWNSTREAM);
- }
-
- InlineTextBox* lastBoxAbove = 0;
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
- if (y >= box->root()->topOverflow()) {
- int bottom = box->root()->nextRootBox() ? box->root()->nextRootBox()->topOverflow() : box->root()->bottomOverflow();
- if (y < bottom) {
- offset = box->offsetForPosition(x);
-
- if (x == box->m_x)
- // the x coordinate is equal to the left edge of this box
- // the affinity must be downstream so the position doesn't jump back to the previous line
- return VisiblePosition(element(), offset + box->m_start, DOWNSTREAM);
-
- if (x < box->m_x + box->m_width)
- // and the x coordinate is to the left of the right edge of this box
- // check to see if position goes in this box
- return VisiblePosition(element(), offset + box->m_start, offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
-
- if (!box->prevOnLine() && x < box->m_x)
- // box is first on line
- // and the x coordinate is to the left of the first text box left edge
- return VisiblePosition(element(), offset + box->m_start, DOWNSTREAM);
-
- if (!box->nextOnLine())
- // box is last on line
- // and the x coordinate is to the right of the last text box right edge
- // generate VisiblePosition, use UPSTREAM affinity if possible
- return VisiblePosition(element(), offset + box->m_start, offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
- }
- lastBoxAbove = box;
- }
- }
-
- return VisiblePosition(element(), lastBoxAbove ? lastBoxAbove->m_start + lastBoxAbove->m_len : 0, DOWNSTREAM);
-}
-
-IntRect RenderText::caretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
-{
- if (!inlineBox)
- return IntRect();
-
- ASSERT(inlineBox->isInlineTextBox());
- if (!inlineBox->isInlineTextBox())
- return IntRect();
-
- InlineTextBox* box = static_cast<InlineTextBox*>(inlineBox);
-
- int height = box->root()->bottomOverflow() - box->root()->topOverflow();
- int top = box->root()->topOverflow();
-
- int left = box->positionForOffset(caretOffset);
-
- int rootLeft = box->root()->xPos();
- // FIXME: should we use the width of the root inline box or the
- // width of the containing block for this?
- if (extraWidthToEndOfLine)
- *extraWidthToEndOfLine = (box->root()->width() + rootLeft) - (left + 1);
-
- int absx, absy;
- absolutePositionForContent(absx, absy);
- left += absx;
- top += absy;
-
- RenderBlock* cb = containingBlock();
- if (style()->autoWrap()) {
- int availableWidth = cb->lineWidth(top);
- if (box->direction() == LTR)
- left = min(left, absx + rootLeft + availableWidth - 1);
- else
- left = max(left, absx + rootLeft);
- }
-
- return IntRect(left, top, 1, height);
-}
-
-ALWAYS_INLINE int RenderText::widthFromCache(const Font& f, int start, int len, int xPos) const
-{
- if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII) {
- int monospaceCharacterWidth = f.spaceWidth();
- int tabWidth = allowTabs() ? monospaceCharacterWidth * 8 : 0;
- int w = 0;
- bool isSpace;
- bool previousCharWasSpace = true; // FIXME: Preserves historical behavior, but seems wrong for start > 0.
- for (int i = start; i < start + len; i++) {
- char c = (*m_text)[i];
- if (c <= ' ') {
- if (c == ' ' || c == '\n') {
- w += monospaceCharacterWidth;
- isSpace = true;
- } else if (c == '\t') {
- w += tabWidth ? tabWidth - ((xPos + w) % tabWidth) : monospaceCharacterWidth;
- isSpace = true;
- } else
- isSpace = false;
- } else {
- w += monospaceCharacterWidth;
- isSpace = false;
- }
- if (isSpace && !previousCharWasSpace)
- w += f.wordSpacing();
- previousCharWasSpace = isSpace;
- }
- return w;
- }
-
- return f.width(TextRun(text()->characters() + start, len, allowTabs(), xPos));
-}
-
-void RenderText::trimmedPrefWidths(int leadWidth,
- int& beginMinW, bool& beginWS,
- int& endMinW, bool& endWS,
- bool& hasBreakableChar, bool& hasBreak,
- int& beginMaxW, int& endMaxW,
- int& minW, int& maxW, bool& stripFrontSpaces)
-{
- bool collapseWhiteSpace = style()->collapseWhiteSpace();
- if (!collapseWhiteSpace)
- stripFrontSpaces = false;
-
- if (m_hasTab || prefWidthsDirty())
- calcPrefWidths(leadWidth);
-
- beginWS = !stripFrontSpaces && m_hasBeginWS;
- endWS = m_hasEndWS;
-
- int len = textLength();
-
- if (!len || (stripFrontSpaces && m_text->containsOnlyWhitespace())) {
- beginMinW = 0;
- endMinW = 0;
- beginMaxW = 0;
- endMaxW = 0;
- minW = 0;
- maxW = 0;
- hasBreak = false;
- return;
- }
-
- minW = m_minWidth;
- maxW = m_maxWidth;
-
- beginMinW = m_beginMinWidth;
- endMinW = m_endMinWidth;
-
- hasBreakableChar = m_hasBreakableChar;
- hasBreak = m_hasBreak;
-
- if ((*m_text)[0] == ' ' || ((*m_text)[0] == '\n' && !style()->preserveNewline()) || (*m_text)[0] == '\t') {
- const Font& f = style()->font(); // FIXME: This ignores first-line.
- if (stripFrontSpaces) {
- const UChar space = ' ';
- int spaceWidth = f.width(TextRun(&space, 1));
- maxW -= spaceWidth;
- } else
- maxW += f.wordSpacing();
- }
-
- stripFrontSpaces = collapseWhiteSpace && m_hasEndWS;
-
- if (!style()->autoWrap() || minW > maxW)
- minW = maxW;
-
- // Compute our max widths by scanning the string for newlines.
- if (hasBreak) {
- const Font& f = style()->font(); // FIXME: This ignores first-line.
- bool firstLine = true;
- beginMaxW = maxW;
- endMaxW = maxW;
- for (int i = 0; i < len; i++) {
- int linelen = 0;
- while (i + linelen < len && (*m_text)[i + linelen] != '\n')
- linelen++;
-
- if (linelen) {
- endMaxW = widthFromCache(f, i, linelen, leadWidth + endMaxW);
- if (firstLine) {
- firstLine = false;
- leadWidth = 0;
- beginMaxW = endMaxW;
- }
- i += linelen;
- } else if (firstLine) {
- beginMaxW = 0;
- firstLine = false;
- leadWidth = 0;
- }
-
- if (i == len - 1)
- // A <pre> run that ends with a newline, as in, e.g.,
- // <pre>Some text\n\n<span>More text</pre>
- endMaxW = 0;
- }
- }
-}
-
-static inline bool isSpaceAccordingToStyle(UChar c, RenderStyle* style)
-{
- return c == ' ' || (c == noBreakSpace && style->nbspMode() == SPACE);
-}
-
-int RenderText::minPrefWidth() const
-{
- if (prefWidthsDirty())
- const_cast<RenderText*>(this)->calcPrefWidths(0);
-
- return m_minWidth;
-}
-
-int RenderText::maxPrefWidth() const
-{
- if (prefWidthsDirty())
- const_cast<RenderText*>(this)->calcPrefWidths(0);
-
- return m_maxWidth;
-}
-
-void RenderText::calcPrefWidths(int leadWidth)
-{
- ASSERT(m_hasTab || prefWidthsDirty());
-
- m_minWidth = 0;
- m_beginMinWidth = 0;
- m_endMinWidth = 0;
- m_maxWidth = 0;
-
- if (isBR())
- return;
-
- int currMinWidth = 0;
- int currMaxWidth = 0;
- m_hasBreakableChar = false;
- m_hasBreak = false;
- m_hasTab = false;
- m_hasBeginWS = false;
- m_hasEndWS = false;
-
- const Font& f = style()->font(); // FIXME: This ignores first-line.
- int wordSpacing = style()->wordSpacing();
- int len = textLength();
- //const UChar* txt = characters();
- bool needsWordSpacing = false;
- bool ignoringSpaces = false;
- bool isSpace = false;
- bool firstWord = true;
- bool firstLine = true;
- int nextBreakable = -1;
- int lastWordBoundary = 0;
-
- bool breakNBSP = style()->autoWrap() && style()->nbspMode() == SPACE;
- bool breakAll = (style()->wordBreak() == BreakAllWordBreak || style()->wordBreak() == BreakWordBreak) && style()->autoWrap();
-
- for (int i = 0; i < len; i++) {
- UChar c = (*m_text)[i];
-
- bool previousCharacterIsSpace = isSpace;
-
- bool isNewline = false;
- if (c == '\n') {
- if (style()->preserveNewline()) {
- m_hasBreak = true;
- isNewline = true;
- isSpace = false;
- } else
- isSpace = true;
- } else if (c == '\t') {
- if (!style()->collapseWhiteSpace()) {
- m_hasTab = true;
- isSpace = false;
- } else
- isSpace = true;
- } else
- isSpace = c == ' ';
-
- if ((isSpace || isNewline) && !i)
- m_hasBeginWS = true;
- if ((isSpace || isNewline) && i == len - 1)
- m_hasEndWS = true;
-
- if (!ignoringSpaces && style()->collapseWhiteSpace() && previousCharacterIsSpace && isSpace)
- ignoringSpaces = true;
-
- if (ignoringSpaces && !isSpace)
- ignoringSpaces = false;
-
- // Ignore spaces and soft hyphens
- if (ignoringSpaces) {
- ASSERT(lastWordBoundary == i);
- lastWordBoundary++;
- continue;
- } else if (c == softHyphen) {
- currMaxWidth += widthFromCache(f, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth);
- lastWordBoundary = i + 1;
- continue;
- }
-
- bool hasBreak = breakAll || isBreakable(m_text->characters(), i, len, nextBreakable, breakNBSP);
- bool betweenWords = true;
- int j = i;
- while (c != '\n' && !isSpaceAccordingToStyle(c, style()) && c != '\t' && c != softHyphen) {
- j++;
- if (j == len)
- break;
- c = (*m_text)[j];
- if (isBreakable(m_text->characters(), j, len, nextBreakable, breakNBSP))
- break;
- if (breakAll) {
- betweenWords = false;
- break;
- }
- }
-
- int wordLen = j - i;
- if (wordLen) {
- int w = widthFromCache(f, i, wordLen, leadWidth + currMaxWidth);
- currMinWidth += w;
- if (betweenWords) {
- if (lastWordBoundary == i)
- currMaxWidth += w;
- else
- currMaxWidth += widthFromCache(f, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth);
- lastWordBoundary = j;
- }
-
- bool isSpace = (j < len) && isSpaceAccordingToStyle(c, style());
- bool isCollapsibleWhiteSpace = (j < len) && style()->isCollapsibleWhiteSpace(c);
- if (j < len && style()->autoWrap())
- m_hasBreakableChar = true;
-
- // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
- // last word in the run.
- if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
- currMaxWidth += wordSpacing;
-
- if (firstWord) {
- firstWord = false;
- // If the first character in the run is breakable, then we consider ourselves to have a beginning
- // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
- // being appended to a previous text run when considering the total minimum width of the containing block.
- if (hasBreak)
- m_hasBreakableChar = true;
- m_beginMinWidth = hasBreak ? 0 : w;
- }
- m_endMinWidth = w;
-
- if (currMinWidth > m_minWidth)
- m_minWidth = currMinWidth;
- currMinWidth = 0;
-
- i += wordLen - 1;
- } else {
- // Nowrap can never be broken, so don't bother setting the
- // breakable character boolean. Pre can only be broken if we encounter a newline.
- if (style()->autoWrap() || isNewline)
- m_hasBreakableChar = true;
-
- if (currMinWidth > m_minWidth)
- m_minWidth = currMinWidth;
- currMinWidth = 0;
-
- if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
- if (firstLine) {
- firstLine = false;
- leadWidth = 0;
- if (!style()->autoWrap())
- m_beginMinWidth = currMaxWidth;
- }
-
- if (currMaxWidth > m_maxWidth)
- m_maxWidth = currMaxWidth;
- currMaxWidth = 0;
- } else {
- currMaxWidth += f.width(TextRun(m_text->characters() + i, 1, allowTabs(), leadWidth + currMaxWidth));
- needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
- }
- ASSERT(lastWordBoundary == i);
- lastWordBoundary++;
- }
- }
-
- if (needsWordSpacing && len > 1 || ignoringSpaces && !firstWord)
- currMaxWidth += wordSpacing;
-
- m_minWidth = max(currMinWidth, m_minWidth);
- m_maxWidth = max(currMaxWidth, m_maxWidth);
-
- if (!style()->autoWrap())
- m_minWidth = m_maxWidth;
-
- if (style()->whiteSpace() == PRE) {
- if (firstLine)
- m_beginMinWidth = m_maxWidth;
- m_endMinWidth = currMaxWidth;
- }
-
- setPrefWidthsDirty(false);
-}
-
-bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
-{
- unsigned currPos;
- for (currPos = from;
- currPos < from + len && ((*m_text)[currPos] == '\n' || (*m_text)[currPos] == ' ' || (*m_text)[currPos] == '\t');
- currPos++) { }
- return currPos >= (from + len);
-}
-
-int RenderText::minXPos() const
-{
- if (!m_firstTextBox)
- return 0;
-
- // FIXME: we should not use an arbitrary value like this. Perhaps we should use INT_MAX.
- int minXPos = 6666666;
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- minXPos = min(minXPos, static_cast<int>(box->m_x));
- return minXPos;
-}
-
-int RenderText::xPos() const
-{
- return m_firstTextBox ? m_firstTextBox->m_x : 0;
-}
-
-int RenderText::yPos() const
-{
- return m_firstTextBox ? m_firstTextBox->m_y : 0;
-}
-
-void RenderText::setSelectionState(SelectionState state)
-{
- InlineTextBox* box;
-
- m_selectionState = state;
- if (state == SelectionStart || state == SelectionEnd || state == SelectionBoth) {
- int startPos, endPos;
- selectionStartEnd(startPos, endPos);
- if (selectionState() == SelectionStart) {
- endPos = textLength();
-
- // to handle selection from end of text to end of line
- if (startPos != 0 && startPos == endPos)
- startPos = endPos - 1;
- } else if (selectionState() == SelectionEnd)
- startPos = 0;
-
- for (box = firstTextBox(); box; box = box->nextTextBox()) {
- if (box->isSelected(startPos, endPos)) {
- RootInlineBox* line = box->root();
- if (line)
- line->setHasSelectedChildren(true);
- }
- }
- } else {
- for (box = firstTextBox(); box; box = box->nextTextBox()) {
- RootInlineBox* line = box->root();
- if (line)
- line->setHasSelectedChildren(state == SelectionInside);
- }
- }
-
- containingBlock()->setSelectionState(state);
-}
-
-void RenderText::setTextWithOffset(PassRefPtr<StringImpl> text, unsigned offset, unsigned len, bool force)
-{
- unsigned oldLen = textLength();
- unsigned newLen = text->length();
- int delta = newLen - oldLen;
- unsigned end = len ? offset + len - 1 : offset;
-
- RootInlineBox* firstRootBox = 0;
- RootInlineBox* lastRootBox = 0;
-
- bool dirtiedLines = false;
-
- // Dirty all text boxes that include characters in between offset and offset+len.
- for (InlineTextBox* curr = firstTextBox(); curr; curr = curr->nextTextBox()) {
- // Text run is entirely before the affected range.
- if (curr->end() < offset)
- continue;
-
- // Text run is entirely after the affected range.
- if (curr->start() > end) {
- curr->offsetRun(delta);
- RootInlineBox* root = curr->root();
- if (!firstRootBox) {
- firstRootBox = root;
- if (!dirtiedLines) {
- // The affected area was in between two runs. Go ahead and mark the root box of
- // the run after the affected area as dirty.
- firstRootBox->markDirty();
- dirtiedLines = true;
- }
- }
- lastRootBox = root;
- } else if (curr->end() >= offset && curr->end() <= end) {
- // Text run overlaps with the left end of the affected range.
- curr->dirtyLineBoxes();
- dirtiedLines = true;
- } else if (curr->start() <= offset && curr->end() >= end) {
- // Text run subsumes the affected range.
- curr->dirtyLineBoxes();
- dirtiedLines = true;
- } else if (curr->start() <= end && curr->end() >= end) {
- // Text run overlaps with right end of the affected range.
- curr->dirtyLineBoxes();
- dirtiedLines = true;
- }
- }
-
- // Now we have to walk all of the clean lines and adjust their cached line break information
- // to reflect our updated offsets.
- if (lastRootBox)
- lastRootBox = lastRootBox->nextRootBox();
- if (firstRootBox) {
- RootInlineBox* prev = firstRootBox->prevRootBox();
- if (prev)
- firstRootBox = prev;
- }
- for (RootInlineBox* curr = firstRootBox; curr && curr != lastRootBox; curr = curr->nextRootBox()) {
- if (curr->lineBreakObj() == this && curr->lineBreakPos() > end)
- curr->setLineBreakPos(curr->lineBreakPos() + delta);
- }
-
- // If the text node is empty, dirty the line where new text will be inserted.
- if (!firstTextBox() && parent()) {
- parent()->dirtyLinesFromChangedChild(this);
- dirtiedLines = true;
- }
-
- m_linesDirty = dirtiedLines;
- setText(text, force);
-}
-
-static inline bool isInlineFlowOrEmptyText(RenderObject* o)
-{
- if (o->isInlineFlow())
- return true;
- if (!o->isText())
- return false;
- StringImpl* text = static_cast<RenderText*>(o)->text();
- if (!text)
- return true;
- return !text->length();
-}
-
-UChar RenderText::previousCharacter()
-{
- // find previous text renderer if one exists
- RenderObject* previousText = this;
- while ((previousText = previousText->previousInPreOrder()))
- if (!isInlineFlowOrEmptyText(previousText))
- break;
- UChar prev = ' ';
- if (previousText && previousText->isText())
- if (StringImpl* previousString = static_cast<RenderText*>(previousText)->text())
- prev = (*previousString)[previousString->length() - 1];
- return prev;
-}
-
-void RenderText::setTextInternal(PassRefPtr<StringImpl> text)
-{
- m_text = text;
- ASSERT(m_text);
-
- m_text = m_text->replace('\\', backslashAsCurrencySymbol());
-
-#if ENABLE(SVG)
- if (isSVGText()) {
- if (style() && style()->whiteSpace() == PRE) {
- // Spec: When xml:space="preserve", the SVG user agent will do the following using a
- // copy of the original character data content. It will convert all newline and tab
- // characters into space characters. Then, it will draw all space characters, including
- // leading, trailing and multiple contiguous space characters.
-
- m_text = m_text->replace('\n', ' ');
-
- // If xml:space="preserve" is set, white-space is set to "pre", which
- // preserves leading, trailing & contiguous space character for us.
- } else {
- // Spec: When xml:space="default", the SVG user agent will do the following using a
- // copy of the original character data content. First, it will remove all newline
- // characters. Then it will convert all tab characters into space characters.
- // Then, it will strip off all leading and trailing space characters.
- // Then, all contiguous space characters will be consolidated.
-
- m_text = m_text->replace('\n', StringImpl::empty());
-
- // If xml:space="default" is set, white-space is set to "nowrap", which handles
- // leading, trailing & contiguous space character removal for us.
- }
-
- m_text = m_text->replace('\t', ' ');
- }
-#endif
-
- if (style()) {
- switch (style()->textTransform()) {
- case TTNONE:
- break;
- case CAPITALIZE: {
- m_text = m_text->capitalize(previousCharacter());
- break;
- }
- case UPPERCASE:
- m_text = m_text->upper();
- break;
- case LOWERCASE:
- m_text = m_text->lower();
- break;
- }
-
- // We use the same characters here as for list markers.
- // See the listMarkerText function in RenderListMarker.cpp.
- switch (style()->textSecurity()) {
- case TSNONE:
- break;
- case TSCIRCLE:
- m_text = m_text->secure(whiteBullet);
- break;
- case TSDISC:
- m_text = m_text->secure(bullet);
- break;
- case TSSQUARE:
- m_text = m_text->secure(blackSquare);
- }
- }
-
- ASSERT(m_text);
- ASSERT(!isBR() || (textLength() == 1 && (*m_text)[0] == '\n'));
-
- m_isAllASCII = charactersAreAllASCII(m_text.get());
-}
-
-void RenderText::setText(PassRefPtr<StringImpl> text, bool force)
-{
- ASSERT(text);
-
- if (!force && equal(m_text.get(), text.get()))
- return;
-
- setTextInternal(text);
- setNeedsLayoutAndPrefWidthsRecalc();
-}
-
-int RenderText::height() const
-{
- int retval = 0;
- if (firstTextBox())
- retval = lastTextBox()->m_y + lastTextBox()->height() - firstTextBox()->m_y;
- return retval;
-}
-
-int RenderText::lineHeight(bool firstLine, bool) const
-{
- // Always use the interior line height of the parent (e.g., if our parent is an inline block).
- return parent()->lineHeight(firstLine, true);
-}
-
-void RenderText::dirtyLineBoxes(bool fullLayout, bool)
-{
- if (fullLayout)
- deleteTextBoxes();
- else if (!m_linesDirty) {
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- box->dirtyLineBoxes();
- }
- m_linesDirty = false;
-}
-
-InlineTextBox* RenderText::createInlineTextBox()
-{
- return new (renderArena()) InlineTextBox(this);
-}
-
-InlineBox* RenderText::createInlineBox(bool, bool isRootLineBox, bool)
-{
- ASSERT(!isRootLineBox);
- InlineTextBox* textBox = createInlineTextBox();
- if (!m_firstTextBox)
- m_firstTextBox = m_lastTextBox = textBox;
- else {
- m_lastTextBox->setNextLineBox(textBox);
- textBox->setPreviousLineBox(m_lastTextBox);
- m_lastTextBox = textBox;
- }
- return textBox;
-}
-
-void RenderText::position(InlineBox* box)
-{
- InlineTextBox* s = static_cast<InlineTextBox*>(box);
-
- // FIXME: should not be needed!!!
- if (!s->m_len) {
- // We want the box to be destroyed.
- s->remove();
- s->destroy(renderArena());
- m_firstTextBox = m_lastTextBox = 0;
- return;
- }
-
- m_containsReversedText |= s->direction() == RTL;
-}
-
-unsigned int RenderText::width(unsigned int from, unsigned int len, int xPos, bool firstLine) const
-{
- if (from >= textLength())
- return 0;
-
- if (from + len > textLength())
- len = textLength() - from;
-
- return width(from, len, style(firstLine)->font(), xPos);
-}
-
-unsigned int RenderText::width(unsigned int from, unsigned int len, const Font& f, int xPos) const
-{
- if (!characters() || from > textLength())
- return 0;
-
- if (from + len > textLength())
- len = textLength() - from;
-
- int w;
- if (&f == &style()->font()) {
- if (!style()->preserveNewline() && !from && len == textLength())
- w = maxPrefWidth();
- else
- w = widthFromCache(f, from, len, xPos);
- } else
- w = f.width(TextRun(text()->characters() + from, len, allowTabs(), xPos));
-
- return w;
-}
-
-int RenderText::width() const
-{
- // FIXME: we should not use an arbitrary value like this. Perhaps we should use INT_MAX.
- int minx = 100000000;
- int maxx = 0;
- // slooow
- for (InlineTextBox* s = firstTextBox(); s; s = s->nextTextBox()) {
- if (s->m_x < minx)
- minx = s->m_x;
- if (s->m_x + s->m_width > maxx)
- maxx = s->m_x + s->m_width;
- }
-
- return max(0, maxx - minx);
-}
-
-IntRect RenderText::absoluteClippedOverflowRect()
-{
- RenderObject* cb = containingBlock();
- return cb->absoluteClippedOverflowRect();
-}
-
-IntRect RenderText::selectionRect(bool clipToVisibleContent)
-{
- ASSERT(!needsLayout());
-
- IntRect rect;
- if (selectionState() == SelectionNone)
- return rect;
- RenderBlock* cb = containingBlock();
- if (!cb)
- return rect;
-
- // Now calculate startPos and endPos for painting selection.
- // We include a selection while endPos > 0
- int startPos, endPos;
- if (selectionState() == SelectionInside) {
- // We are fully selected.
- startPos = 0;
- endPos = textLength();
- } else {
- selectionStartEnd(startPos, endPos);
- if (selectionState() == SelectionStart)
- endPos = textLength();
- else if (selectionState() == SelectionEnd)
- startPos = 0;
- }
-
- if (startPos == endPos)
- return rect;
-
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- rect.unite(box->selectionRect(0, 0, startPos, endPos));
-
- if (clipToVisibleContent)
- computeAbsoluteRepaintRect(rect);
- else {
- if (cb->hasColumns())
- cb->adjustRectForColumns(rect);
- int absx, absy;
- absolutePosition(absx, absy);
- rect.move(absx, absy);
- }
-
- return rect;
-}
-
-int RenderText::verticalPositionHint(bool firstLine) const
-{
- if (parent()->isReplaced())
- return 0; // Treat inline blocks just like blocks. There can't be any vertical position hint.
- return parent()->verticalPositionHint(firstLine);
-}
-
-int RenderText::caretMinOffset() const
-{
- InlineTextBox* box = firstTextBox();
- if (!box)
- return 0;
- int minOffset = box->m_start;
- for (box = box->nextTextBox(); box; box = box->nextTextBox())
- minOffset = min(minOffset, box->m_start);
- return minOffset;
-}
-
-int RenderText::caretMaxOffset() const
-{
- InlineTextBox* box = lastTextBox();
- if (!box)
- return textLength();
- int maxOffset = box->m_start + box->m_len;
- for (box = box->prevTextBox(); box; box = box->prevTextBox())
- maxOffset = max(maxOffset, box->m_start + box->m_len);
- return maxOffset;
-}
-
-unsigned RenderText::caretMaxRenderedOffset() const
-{
- int l = 0;
- for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox())
- l += box->m_len;
- return l;
-}
-
-int RenderText::previousOffset(int current) const
-{
- StringImpl* si = m_text.get();
- TextBreakIterator* iterator = characterBreakIterator(si->characters(), si->length());
- if (!iterator)
- return current - 1;
-
- long result = textBreakPreceding(iterator, current);
- if (result == TextBreakDone)
- result = current - 1;
-
- return result;
-}
-
-int RenderText::nextOffset(int current) const
-{
- StringImpl* si = m_text.get();
- TextBreakIterator* iterator = characterBreakIterator(si->characters(), si->length());
- if (!iterator)
- return current + 1;
-
- long result = textBreakFollowing(iterator, current);
- if (result == TextBreakDone)
- result = current + 1;
-
- return result;
-}
-
-#ifndef NDEBUG
-
-void RenderText::checkConsistency() const
-{
-#ifdef CHECK_CONSISTENCY
- const InlineTextBox* prev = 0;
- for (const InlineTextBox* child = m_firstTextBox; child != 0; child = child->nextTextBox()) {
- ASSERT(child->object() == this);
- ASSERT(child->prevTextBox() == prev);
- prev = child;
- }
- ASSERT(prev == m_lastTextBox);
-#endif
-}
-
-#endif
-
-} // namespace WebCore
diff --git a/webkit/pending/RenderTextControl.cpp b/webkit/pending/RenderTextControl.cpp
deleted file mode 100644
index ee74714..0000000
--- a/webkit/pending/RenderTextControl.cpp
+++ /dev/null
@@ -1,1306 +0,0 @@
-/**
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "RenderTextControl.h"
-
-#include "CharacterNames.h"
-#include "CSSStyleSelector.h"
-#include "Document.h"
-#include "Editor.h"
-#include "EditorClient.h"
-#include "Event.h"
-#include "EventNames.h"
-#include "FontSelector.h"
-#include "Frame.h"
-#include "HTMLBRElement.h"
-#include "HTMLInputElement.h"
-#include "HTMLNames.h"
-#include "HTMLTextAreaElement.h"
-#include "HitTestResult.h"
-#include "LocalizedStrings.h"
-#include "MouseEvent.h"
-#include "PlatformKeyboardEvent.h"
-#include "PlatformScrollBar.h"
-#include "RenderTheme.h"
-#include "SearchPopupMenu.h"
-#include "SelectionController.h"
-#include "Settings.h"
-#include "SimpleFontData.h"
-#include "Text.h"
-#include "TextControlInnerElements.h"
-#include "TextIterator.h"
-#include "htmlediting.h"
-#include "visible_units.h"
-#include <math.h>
-
-using namespace std;
-
-namespace WebCore {
-
-using namespace EventNames;
-using namespace HTMLNames;
-
-class RenderTextControlInnerBlock : public RenderBlock {
-public:
- RenderTextControlInnerBlock(Node* node, bool isMultiLine) : RenderBlock(node), m_multiLine(isMultiLine) { }
-
- virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
- virtual VisiblePosition positionForCoordinates(int x, int y);
-private:
- bool m_multiLine;
-};
-
-VisiblePosition RenderTextControlInnerBlock::positionForCoordinates(int x, int y)
-{
- int contentsX = x;
- int contentsY = y;
-
- // Multiline text controls have the scroll on shadowAncestorNode, so we need to take that
- // into account here.
- if (m_multiLine) {
- RenderTextControl* renderer = static_cast<RenderTextControl*>(node()->shadowAncestorNode()->renderer());
- if (renderer->hasOverflowClip())
- renderer->layer()->scrollOffset(contentsX, contentsY);
- }
-
- return RenderBlock::positionForCoordinates(contentsX, contentsY);
-}
-
-RenderTextControl::RenderTextControl(Node* node, bool multiLine)
- : RenderBlock(node)
- , m_dirty(false)
- , m_multiLine(multiLine)
- , m_placeholderVisible(false)
- , m_userEdited(false)
- , m_shouldDrawCapsLockIndicator(false)
- , m_searchPopup(0)
- , m_searchPopupIsVisible(false)
- , m_searchEventTimer(this, &RenderTextControl::searchEventTimerFired)
-{
-}
-
-RenderTextControl::~RenderTextControl()
-{
- if (m_searchPopup) {
- m_searchPopup->disconnectClient();
- m_searchPopup = 0;
- }
- if (m_multiLine && node())
- static_cast<HTMLTextAreaElement*>(node())->rendererWillBeDestroyed();
- // The children renderers have already been destroyed by destroyLeftoverChildren
- if (m_innerBlock)
- m_innerBlock->detach();
- else if (m_innerText)
- m_innerText->detach();
-}
-
-void RenderTextControl::setStyle(RenderStyle* style)
-{
- RenderBlock::setStyle(style);
- if (m_innerBlock) {
- // We may have set the width and the height in the old style in layout(). Reset them now to avoid
- // getting a spurious layout hint.
- m_innerBlock->renderer()->style()->setHeight(Length());
- m_innerBlock->renderer()->style()->setWidth(Length());
- m_innerBlock->renderer()->setStyle(createInnerBlockStyle(style));
- }
-
- if (m_innerText) {
- RenderBlock* textBlockRenderer = static_cast<RenderBlock*>(m_innerText->renderer());
- RenderStyle* textBlockStyle = createInnerTextStyle(style);
- // We may have set the width and the height in the old style in layout(). Reset them now to avoid
- // getting a spurious layout hint.
- textBlockRenderer->style()->setHeight(Length());
- textBlockRenderer->style()->setWidth(Length());
- textBlockRenderer->setStyle(textBlockStyle);
- for (Node* n = m_innerText->firstChild(); n; n = n->traverseNextNode(m_innerText.get())) {
- if (n->renderer())
- n->renderer()->setStyle(textBlockStyle);
- }
- }
- if (m_resultsButton)
- m_resultsButton->renderer()->setStyle(createResultsButtonStyle(style));
-
- if (m_cancelButton)
- m_cancelButton->renderer()->setStyle(createCancelButtonStyle(style));
-
- if (!m_multiLine)
- setHasOverflowClip(false);
-
- setReplaced(isInline());
-}
-
-static Color disabledTextColor(const Color& textColor, const Color& backgroundColor)
-{
- // The explcit check for black is an optimization for the 99% case (black on white).
- // This also means that black on black will turn into grey on black when disabled.
- if (textColor.rgb() == Color::black || differenceSquared(textColor, Color::white) > differenceSquared(backgroundColor, Color::white))
- return textColor.light();
- return textColor.dark();
-}
-
-RenderStyle* RenderTextControl::createInnerBlockStyle(RenderStyle* startStyle)
-{
- RenderStyle* innerBlockStyle = new (renderArena()) RenderStyle();
-
- innerBlockStyle->inheritFrom(startStyle);
- innerBlockStyle->setDisplay(BLOCK);
- innerBlockStyle->setDirection(LTR);
- // We don't want the shadow dom to be editable, so we set this block to read-only in case the input itself is editable.
- innerBlockStyle->setUserModify(READ_ONLY);
-
- return innerBlockStyle;
-}
-
-RenderStyle* RenderTextControl::createInnerTextStyle(RenderStyle* startStyle)
-{
- RenderStyle* textBlockStyle = new (renderArena()) RenderStyle();
- HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(node());
-
- textBlockStyle->inheritFrom(startStyle);
- // The inner block, if present, always has its direction set to LTR,
- // so we need to inherit the direction from the element.
- textBlockStyle->setDirection(style()->direction());
- textBlockStyle->setUserModify(element->isReadOnlyControl() || element->disabled() ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY);
- if (m_innerBlock)
- textBlockStyle->setDisplay(INLINE_BLOCK);
- else
- textBlockStyle->setDisplay(BLOCK);
-
- if (m_multiLine) {
- // The inner text block should not ever have scrollbars.
- textBlockStyle->setOverflowX(OVISIBLE);
- textBlockStyle->setOverflowY(OVISIBLE);
-
- // Set word wrap property based on wrap attribute.
- if (!static_cast<HTMLTextAreaElement*>(element)->shouldWrapText()) {
- textBlockStyle->setWhiteSpace(PRE);
- textBlockStyle->setWordWrap(NormalWordWrap);
- } else {
- textBlockStyle->setWhiteSpace(PRE_WRAP);
- textBlockStyle->setWordWrap(BreakWordWrap);
- }
- } else {
- textBlockStyle->setWhiteSpace(PRE);
- textBlockStyle->setWordWrap(NormalWordWrap);
- textBlockStyle->setOverflowX(OHIDDEN);
- textBlockStyle->setOverflowY(OHIDDEN);
-
- // Do not allow line-height to be smaller than our default.
- if (textBlockStyle->font().lineSpacing() > lineHeight(true, true))
- textBlockStyle->setLineHeight(Length(-100.0f, Percent));
- }
-
- if (!m_multiLine) {
- // We're adding one extra pixel of padding to match WinIE.
- textBlockStyle->setPaddingLeft(Length(1, Fixed));
- textBlockStyle->setPaddingRight(Length(1, Fixed));
- }
-
- if (!element->isEnabled())
- textBlockStyle->setColor(disabledTextColor(startStyle->color(), startStyle->backgroundColor()));
-
- return textBlockStyle;
-}
-
-RenderStyle* RenderTextControl::createResultsButtonStyle(RenderStyle* startStyle)
-{
- ASSERT(!m_multiLine);
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
- RenderStyle* resultsBlockStyle;
- if (input->maxResults() < 0)
- resultsBlockStyle = getPseudoStyle(RenderStyle::SEARCH_DECORATION);
- else if (!input->maxResults())
- resultsBlockStyle = getPseudoStyle(RenderStyle::SEARCH_RESULTS_DECORATION);
- else
- resultsBlockStyle = getPseudoStyle(RenderStyle::SEARCH_RESULTS_BUTTON);
-
- if (!resultsBlockStyle)
- resultsBlockStyle = new (renderArena()) RenderStyle();
-
- if (startStyle)
- resultsBlockStyle->inheritFrom(startStyle);
-
- resultsBlockStyle->setDisplay(INLINE_BLOCK);
-
- return resultsBlockStyle;
-}
-
-RenderStyle* RenderTextControl::createCancelButtonStyle(RenderStyle* startStyle)
-{
- RenderStyle* cancelBlockStyle;
-
- if (RenderStyle* pseudoStyle = getPseudoStyle(RenderStyle::SEARCH_CANCEL_BUTTON))
- // We may be sharing style with another search field, but we must not share the cancel button style.
- cancelBlockStyle = new (renderArena()) RenderStyle(*pseudoStyle);
- else
- cancelBlockStyle = new (renderArena()) RenderStyle();
-
- if (startStyle)
- cancelBlockStyle->inheritFrom(startStyle);
-
- cancelBlockStyle->setDisplay(INLINE_BLOCK);
-
- updateCancelButtonVisibility(cancelBlockStyle);
-
- return cancelBlockStyle;
-}
-
-void RenderTextControl::updatePlaceholder()
-{
- bool oldPlaceholderVisible = m_placeholderVisible;
-
- String placeholder;
- if (!m_multiLine) {
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
- if (input->value().isEmpty() && document()->focusedNode() != node())
- placeholder = input->getAttribute(placeholderAttr);
- }
-
- if (!placeholder.isEmpty() || m_placeholderVisible) {
- ExceptionCode ec = 0;
- m_innerText->setInnerText(placeholder, ec);
- m_placeholderVisible = !placeholder.isEmpty();
- }
-
- Color color;
- if (!placeholder.isEmpty())
- color = Color::darkGray;
- else if (node()->isEnabled())
- color = style()->color();
- else
- color = disabledTextColor(style()->color(), style()->backgroundColor());
-
- RenderObject* renderer = m_innerText->renderer();
- RenderStyle* innerStyle = renderer->style();
- if (innerStyle->color() != color) {
- innerStyle->setColor(color);
- renderer->repaint();
- }
-
- // temporary disable textSecurity if placeholder is visible
- if (style()->textSecurity() != TSNONE && oldPlaceholderVisible != m_placeholderVisible) {
- RenderStyle* newInnerStyle = new (renderArena()) RenderStyle(*innerStyle);
- newInnerStyle->setTextSecurity(m_placeholderVisible ? TSNONE : style()->textSecurity());
- renderer->setStyle(newInnerStyle);
- for (Node* n = m_innerText->firstChild(); n; n = n->traverseNextNode(m_innerText.get())) {
- if (n->renderer())
- n->renderer()->setStyle(newInnerStyle);
- }
- }
-}
-
-void RenderTextControl::createSubtreeIfNeeded()
-{
- // When adding these elements, create the renderer & style first before adding to the DOM.
- // Otherwise, the render tree will create some anonymous blocks that will mess up our layout.
- bool isSearchField = !m_multiLine && static_cast<HTMLInputElement*>(node())->isSearchField();
- if (isSearchField && !m_innerBlock) {
- // Create the inner block element and give it a parent, renderer, and style
- m_innerBlock = new TextControlInnerElement(document(), node());
- RenderBlock* innerBlockRenderer = new (renderArena()) RenderBlock(m_innerBlock.get());
- m_innerBlock->setRenderer(innerBlockRenderer);
- m_innerBlock->setAttached();
- m_innerBlock->setInDocument(true);
- innerBlockRenderer->setStyle(createInnerBlockStyle(style()));
-
- // Add inner block renderer to Render tree
- RenderBlock::addChild(innerBlockRenderer);
- }
- if (isSearchField && !m_resultsButton) {
- // Create the results block element and give it a parent, renderer, and style
- m_resultsButton = new SearchFieldResultsButtonElement(document());
- RenderBlock* resultsBlockRenderer = new (renderArena()) RenderBlock(m_resultsButton.get());
- m_resultsButton->setRenderer(resultsBlockRenderer);
- m_resultsButton->setAttached();
- m_resultsButton->setInDocument(true);
-
- RenderStyle* resultsBlockStyle = createResultsButtonStyle(m_innerBlock->renderer()->style());
- resultsBlockRenderer->setStyle(resultsBlockStyle);
-
- // Add results renderer to DOM & Render tree
- m_innerBlock->renderer()->addChild(resultsBlockRenderer);
- ExceptionCode ec = 0;
- m_innerBlock->appendChild(m_resultsButton, ec);
- }
- if (!m_innerText) {
- // Create the text block element and give it a parent, renderer, and style
- // For non-search fields, there is no intermediate m_innerBlock as the shadow node.
- // m_innerText will be the shadow node in that case.
- m_innerText = new TextControlInnerTextElement(document(), m_innerBlock ? 0 : node());
- RenderTextControlInnerBlock* textBlockRenderer = new (renderArena()) RenderTextControlInnerBlock(m_innerText.get(), m_multiLine);
- m_innerText->setRenderer(textBlockRenderer);
- m_innerText->setAttached();
- m_innerText->setInDocument(true);
-
- RenderStyle* parentStyle = style();
- if (m_innerBlock)
- parentStyle = m_innerBlock->renderer()->style();
- RenderStyle* textBlockStyle = createInnerTextStyle(parentStyle);
- textBlockRenderer->setStyle(textBlockStyle);
-
- // Add text block renderer to Render tree
- if (m_innerBlock) {
- m_innerBlock->renderer()->addChild(textBlockRenderer);
- ExceptionCode ec = 0;
- // Add text block to the DOM
- m_innerBlock->appendChild(m_innerText, ec);
- } else
- RenderBlock::addChild(textBlockRenderer);
- }
- if (isSearchField && !m_cancelButton) {
- // Create the close block element and give it a parent, renderer, and style
- m_cancelButton = new SearchFieldCancelButtonElement(document());
- RenderBlock* closeBlockRenderer = new (renderArena()) RenderBlock(m_cancelButton.get());
- m_cancelButton->setRenderer(closeBlockRenderer);
- m_cancelButton->setAttached();
- m_cancelButton->setInDocument(true);
-
- RenderStyle* closeBlockStyle = createCancelButtonStyle(m_innerBlock->renderer()->style());
- closeBlockRenderer->setStyle(closeBlockStyle);
-
- // Add close block renderer to DOM & Render tree
- m_innerBlock->renderer()->addChild(closeBlockRenderer);
- ExceptionCode ec = 0;
- m_innerBlock->appendChild(m_cancelButton, ec);
- }
-}
-
-void RenderTextControl::updateFromElement()
-{
- HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(node());
-
- createSubtreeIfNeeded();
-
- if (m_cancelButton)
- updateCancelButtonVisibility(m_cancelButton->renderer()->style());
-
- updatePlaceholder();
-
- m_innerText->renderer()->style()->setUserModify(element->isReadOnlyControl() || element->disabled() ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY);
-
- if ((!element->valueMatchesRenderer() || m_multiLine) && !m_placeholderVisible) {
- String value;
- if (m_multiLine)
- value = static_cast<HTMLTextAreaElement*>(element)->value();
- else
- value = static_cast<HTMLInputElement*>(element)->value();
- if (value.isNull())
- value = "";
- else
- value = value.replace('\\', backslashAsCurrencySymbol());
- if (value != text() || !m_innerText->hasChildNodes()) {
- if (value != text()) {
- if (Frame* frame = document()->frame())
- frame->editor()->clearUndoRedoOperations();
- }
- ExceptionCode ec = 0;
- m_innerText->setInnerText(value, ec);
- if (value.endsWith("\n") || value.endsWith("\r"))
- m_innerText->appendChild(new HTMLBRElement(document()), ec);
- m_dirty = false;
- m_userEdited = false;
- }
- element->setValueMatchesRenderer();
- }
-
- if (m_searchPopupIsVisible)
- m_searchPopup->updateFromElement();
-}
-
-void RenderTextControl::setUserEdited(bool isUserEdited)
-{
- m_userEdited = isUserEdited;
- document()->setIgnoreAutofocus(isUserEdited);
-}
-
-int RenderTextControl::selectionStart()
-{
- Frame* frame = document()->frame();
- if (!frame)
- return 0;
- return indexForVisiblePosition(frame->selection()->start());
-}
-
-int RenderTextControl::selectionEnd()
-{
- Frame* frame = document()->frame();
- if (!frame)
- return 0;
- return indexForVisiblePosition(frame->selection()->end());
-}
-
-void RenderTextControl::setSelectionStart(int start)
-{
- setSelectionRange(start, max(start, selectionEnd()));
-}
-
-void RenderTextControl::setSelectionEnd(int end)
-{
- setSelectionRange(min(end, selectionStart()), end);
-}
-
-void RenderTextControl::select()
-{
- setSelectionRange(0, text().length());
-}
-
-void RenderTextControl::setSelectionRange(int start, int end)
-{
- end = max(end, 0);
- start = min(max(start, 0), end);
-
- document()->updateLayout();
-
- if (style()->visibility() == HIDDEN || !m_innerText || !m_innerText->renderer() || !m_innerText->renderer()->height()) {
- if (m_multiLine)
- static_cast<HTMLTextAreaElement*>(node())->cacheSelection(start, end);
- else
- static_cast<HTMLInputElement*>(node())->cacheSelection(start, end);
- return;
- }
- VisiblePosition startPosition = visiblePositionForIndex(start);
- VisiblePosition endPosition;
- if (start == end)
- endPosition = startPosition;
- else
- endPosition = visiblePositionForIndex(end);
-
- ASSERT(startPosition.isNotNull() && endPosition.isNotNull());
- ASSERT(startPosition.deepEquivalent().node()->shadowAncestorNode() == node() && endPosition.deepEquivalent().node()->shadowAncestorNode() == node());
-
- Selection newSelection = Selection(startPosition, endPosition);
-
- if (Frame* frame = document()->frame())
- frame->selection()->setSelection(newSelection);
-
- // FIXME: Granularity is stored separately on the frame, but also in the selection controller.
- // The granularity in the selection controller should be used, and then this line of code would not be needed.
- if (Frame* frame = document()->frame())
- frame->setSelectionGranularity(CharacterGranularity);
-}
-
-Selection RenderTextControl::selection(int start, int end) const
-{
- return Selection(VisiblePosition(m_innerText.get(), start, VP_DEFAULT_AFFINITY),
- VisiblePosition(m_innerText.get(), end, VP_DEFAULT_AFFINITY));
-}
-
-VisiblePosition RenderTextControl::visiblePositionForIndex(int index)
-{
- if (index <= 0)
- return VisiblePosition(m_innerText.get(), 0, DOWNSTREAM);
- ExceptionCode ec = 0;
- RefPtr<Range> range = Range::create(document());
- range->selectNodeContents(m_innerText.get(), ec);
- CharacterIterator it(range.get());
- it.advance(index - 1);
- return VisiblePosition(it.range()->endContainer(ec), it.range()->endOffset(ec), UPSTREAM);
-}
-
-int RenderTextControl::indexForVisiblePosition(const VisiblePosition& pos)
-{
- Position indexPosition = pos.deepEquivalent();
- if (!indexPosition.node() || indexPosition.node()->rootEditableElement() != m_innerText)
- return 0;
- ExceptionCode ec = 0;
- RefPtr<Range> range = Range::create(document());
- range->setStart(m_innerText.get(), 0, ec);
- range->setEnd(indexPosition.node(), indexPosition.offset(), ec);
- return TextIterator::rangeLength(range.get());
-}
-
-void RenderTextControl::updateCancelButtonVisibility(RenderStyle* style)
-{
- ASSERT(!m_multiLine);
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
- if (input->value().isEmpty())
- style->setVisibility(HIDDEN);
- else
- style->setVisibility(VISIBLE);
-}
-
-void RenderTextControl::subtreeHasChanged()
-{
- bool wasDirty = m_dirty;
- m_dirty = true;
- m_userEdited = true;
- HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(node());
- if (m_multiLine) {
- element->setValueMatchesRenderer(false);
- if (element->focused())
- if (Frame* frame = document()->frame())
- frame->textDidChangeInTextArea(element);
- } else {
- HTMLInputElement* input = static_cast<HTMLInputElement*>(element);
- input->setValueFromRenderer(input->constrainValue(text()));
- if (m_cancelButton)
- updateCancelButtonVisibility(m_cancelButton->renderer()->style());
-
- // If the incremental attribute is set, then dispatch the search event
- if (!input->getAttribute(incrementalAttr).isNull())
- startSearchEventTimer();
-
- if (!wasDirty) {
- if (input->focused())
- if (Frame* frame = document()->frame())
- frame->textFieldDidBeginEditing(input);
- }
- if (input->focused())
- if (Frame* frame = document()->frame())
- frame->textDidChangeInTextField(input);
- }
-}
-
-String RenderTextControl::finishText(Vector<UChar>& result) const
-{
- // Remove one trailing newline; there's always one that's collapsed out by rendering.
- size_t size = result.size();
- if (size && result[size - 1] == '\n')
- result.shrink(--size);
-
- // Convert backslash to currency symbol.
- UChar symbol = backslashAsCurrencySymbol();
- if (symbol != '\\') {
- for (size_t i = 0; i < size; ++i) {
- if (result[i] == '\\')
- result[i] = symbol;
- }
- }
-
- return String::adopt(result);
-}
-
-HTMLElement* RenderTextControl::innerTextElement() const
-{
- return m_innerText.get();
-}
-
-String RenderTextControl::text()
-{
- if (!m_innerText)
- return "";
-
- Frame* frame = document()->frame();
- Text* compositionNode = frame ? frame->editor()->compositionNode() : 0;
-
- Vector<UChar> result;
-
- for (Node* n = m_innerText.get(); n; n = n->traverseNextNode(m_innerText.get())) {
- if (n->isTextNode()) {
- Text* text = static_cast<Text*>(n);
- String data = text->data();
- unsigned length = data.length();
- if (text != compositionNode)
- result.append(data.characters(), length);
- else {
- unsigned compositionStart = min(frame->editor()->compositionStart(), length);
- unsigned compositionEnd = min(max(compositionStart, frame->editor()->compositionEnd()), length);
- result.append(data.characters(), compositionStart);
- result.append(data.characters() + compositionEnd, length - compositionEnd);
- }
- }
- }
-
- return finishText(result);
-}
-
-static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& breakOffset)
-{
- RootInlineBox* next;
- for (; line; line = next) {
- next = line->nextRootBox();
- if (next && !line->endsWithBreak()) {
- ASSERT(line->lineBreakObj());
- breakNode = line->lineBreakObj()->node();
- breakOffset = line->lineBreakPos();
- line = next;
- return;
- }
- }
- breakNode = 0;
-}
-
-String RenderTextControl::textWithHardLineBreaks()
-{
- if (!m_innerText)
- return "";
- Node* firstChild = m_innerText->firstChild();
- if (!firstChild)
- return "";
-
- document()->updateLayout();
-
- RenderObject* renderer = firstChild->renderer();
- if (!renderer)
- return "";
-
- InlineBox* box = renderer->isText() ? static_cast<RenderText*>(renderer)->firstTextBox() : renderer->inlineBoxWrapper();
- if (!box)
- return "";
-
- Frame* frame = document()->frame();
- Text* compositionNode = frame ? frame->editor()->compositionNode() : 0;
-
- Node* breakNode;
- unsigned breakOffset;
- RootInlineBox* line = box->root();
- getNextSoftBreak(line, breakNode, breakOffset);
-
- Vector<UChar> result;
-
- for (Node* n = firstChild; n; n = n->traverseNextNode(m_innerText.get())) {
- if (n->hasTagName(brTag))
- result.append(&newlineCharacter, 1);
- else if (n->isTextNode()) {
- Text* text = static_cast<Text*>(n);
- String data = text->data();
- unsigned length = data.length();
- unsigned compositionStart = (text == compositionNode)
- ? min(frame->editor()->compositionStart(), length) : 0;
- unsigned compositionEnd = (text == compositionNode)
- ? min(max(compositionStart, frame->editor()->compositionEnd()), length) : 0;
- unsigned position = 0;
- while (breakNode == n && breakOffset < compositionStart) {
- result.append(data.characters() + position, breakOffset - position);
- position = breakOffset;
- result.append(&newlineCharacter, 1);
- getNextSoftBreak(line, breakNode, breakOffset);
- }
- result.append(data.characters() + position, compositionStart - position);
- position = compositionEnd;
- while (breakNode == n && breakOffset <= length) {
- if (breakOffset > position) {
- result.append(data.characters() + position, breakOffset - position);
- position = breakOffset;
- result.append(&newlineCharacter, 1);
- }
- getNextSoftBreak(line, breakNode, breakOffset);
- }
- result.append(data.characters() + position, length - position);
- }
- while (breakNode == n)
- getNextSoftBreak(line, breakNode, breakOffset);
- }
-
- return finishText(result);
-}
-
-void RenderTextControl::calcHeight()
-{
- int rows = 1;
- if (m_multiLine)
- rows = static_cast<HTMLTextAreaElement*>(node())->rows();
-
- int line = m_innerText->renderer()->lineHeight(true, true);
- int toAdd = paddingTop() + paddingBottom() + borderTop() + borderBottom();
-
- int innerToAdd = m_innerText->renderer()->borderTop() + m_innerText->renderer()->borderBottom() +
- m_innerText->renderer()->paddingTop() + m_innerText->renderer()->paddingBottom() +
- m_innerText->renderer()->marginTop() + m_innerText->renderer()->marginBottom();
-
- if (m_resultsButton) {
- static_cast<RenderBlock*>(m_resultsButton->renderer())->calcHeight();
- innerToAdd = max(innerToAdd,
- m_resultsButton->renderer()->borderTop() + m_resultsButton->renderer()->borderBottom() +
- m_resultsButton->renderer()->paddingTop() + m_resultsButton->renderer()->paddingBottom() +
- m_resultsButton->renderer()->marginTop() + m_resultsButton->renderer()->marginBottom());
- line = max(line, m_resultsButton->renderer()->height());
- }
- if (m_cancelButton) {
- static_cast<RenderBlock*>(m_cancelButton->renderer())->calcHeight();
- innerToAdd = max(innerToAdd,
- m_cancelButton->renderer()->borderTop() + m_cancelButton->renderer()->borderBottom() +
- m_cancelButton->renderer()->paddingTop() + m_cancelButton->renderer()->paddingBottom() +
- m_cancelButton->renderer()->marginTop() + m_cancelButton->renderer()->marginBottom());
- line = max(line, m_cancelButton->renderer()->height());
- }
- toAdd += innerToAdd;
-
- // FIXME: We should get the size of the scrollbar from the RenderTheme instead.
- int scrollbarSize = 0;
- // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap.
- if (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && m_innerText->renderer()->style()->wordWrap() == NormalWordWrap))
- scrollbarSize = PlatformScrollbar::horizontalScrollbarHeight();
-
- m_height = line * rows + toAdd + scrollbarSize;
-
- RenderBlock::calcHeight();
-}
-
-int RenderTextControl::baselinePosition(bool b, bool isRootLineBox) const
-{
- if (m_multiLine)
- return height() + marginTop() + marginBottom();
- return RenderBlock::baselinePosition(b, isRootLineBox);
-}
-
-bool RenderTextControl::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
-{
- // If we're within the text control, we want to act as if we've hit the inner text block element, in case the point
- // was on the control but not on the inner element (see Radar 4617841).
-
- // In a search field, we want to act as if we've hit the results block if we're to the left of the inner text block,
- // and act as if we've hit the close block if we're to the right of the inner text block.
-
- if (RenderBlock::nodeAtPoint(request, result, x, y, tx, ty, hitTestAction) &&
- (m_multiLine || result.innerNode() == element() || result.innerNode() == m_innerBlock)) {
- IntPoint localPoint = IntPoint(x - tx - m_x, y - ty - m_y);
- if (m_innerBlock) {
- int textLeft = tx + m_x + m_innerBlock->renderer()->xPos() + m_innerText->renderer()->xPos();
- int textRight = textLeft + m_innerText->renderer()->width();
- if (m_resultsButton && x < textLeft) {
- result.setInnerNode(m_resultsButton.get());
- result.setLocalPoint(IntPoint(localPoint.x() - m_innerText->renderer()->xPos() - m_innerBlock->renderer()->xPos() - m_resultsButton->renderer()->xPos(),
- localPoint.y() - m_innerText->renderer()->yPos() - m_innerBlock->renderer()->yPos() - m_resultsButton->renderer()->yPos()));
- return true;
- }
- if (m_cancelButton && x > textRight) {
- result.setInnerNode(m_cancelButton.get());
- result.setLocalPoint(IntPoint(localPoint.x() - m_innerText->renderer()->xPos() - m_innerBlock->renderer()->xPos() - m_cancelButton->renderer()->xPos(),
- localPoint.y() - m_innerText->renderer()->yPos() - m_innerBlock->renderer()->yPos() - m_cancelButton->renderer()->yPos()));
- return true;
- }
- }
-
- // Hit the inner text block.
- result.setInnerNode(m_innerText.get());
- result.setInnerNonSharedNode(m_innerText.get());
- result.setLocalPoint(IntPoint(localPoint.x() - m_innerText->renderer()->xPos() - (m_innerBlock.get() ? m_innerBlock->renderer()->xPos() : 0),
- localPoint.y() - m_innerText->renderer()->yPos() - (m_innerBlock.get() ? m_innerBlock->renderer()->yPos() : 0)));
-
- return true;
- }
-
- return false;
-}
-
-IntRect RenderTextControl::controlClipRect(int tx, int ty) const
-{
- IntRect clipRect = contentBox();
- clipRect.move(tx, ty);
- return clipRect;
-}
-
-void RenderTextControl::layout()
-{
- int oldHeight = m_height;
- calcHeight();
- bool relayoutChildren = oldHeight != m_height;
-
- // Set the text block's height
- int textBlockHeight = m_height - paddingTop() - paddingBottom() - borderTop() - borderBottom();
- int currentTextBlockHeight = m_innerText->renderer()->height();
- if (m_multiLine || m_innerBlock || currentTextBlockHeight > m_height) {
- if (textBlockHeight != currentTextBlockHeight)
- relayoutChildren = true;
- if (!m_multiLine)
- m_innerText->renderer()->style()->setHeight(Length(textBlockHeight, Fixed));
- }
- if (m_innerBlock) {
- if (textBlockHeight != m_innerBlock->renderer()->height())
- relayoutChildren = true;
- m_innerBlock->renderer()->style()->setHeight(Length(textBlockHeight, Fixed));
- }
-
- int oldWidth = m_width;
- calcWidth();
- if (oldWidth != m_width)
- relayoutChildren = true;
-
- int searchExtrasWidth = 0;
- if (m_resultsButton) {
- m_resultsButton->renderer()->calcWidth();
- searchExtrasWidth += m_resultsButton->renderer()->width();
- }
- if (m_cancelButton) {
- m_cancelButton->renderer()->calcWidth();
- searchExtrasWidth += m_cancelButton->renderer()->width();
- }
-
- int scrollbarSize = 0;
- if (m_multiLine && style()->overflowY() != OHIDDEN)
- // FIXME: We should get the size of the scrollbar from the RenderTheme instead.
- scrollbarSize = PlatformScrollbar::verticalScrollbarWidth();
-
- // Set the text block's width
- int textBlockWidth = m_width - paddingLeft() - paddingRight() - borderLeft() - borderRight() -
- m_innerText->renderer()->paddingLeft() - m_innerText->renderer()->paddingRight() - searchExtrasWidth -
- scrollbarSize;
-
- if (m_multiLine && style()->htmlHacks())
- // Matches width in IE quirksmode. We can't just remove the CSS padding in
- // quirks.css because then text will wrap differently than in IE.
- textBlockWidth -= 2;
-
- if (textBlockWidth != m_innerText->renderer()->width())
- relayoutChildren = true;
- m_innerText->renderer()->style()->setWidth(Length(textBlockWidth, Fixed));
- if (m_innerBlock) {
- int innerBlockWidth = m_width - paddingLeft() - paddingRight() - borderLeft() - borderRight();
- if (innerBlockWidth != m_innerBlock->renderer()->width())
- relayoutChildren = true;
- m_innerBlock->renderer()->style()->setWidth(Length(innerBlockWidth, Fixed));
- }
-
- RenderBlock::layoutBlock(relayoutChildren);
-
- // For text fields, center the inner text vertically
- // Don't do this for search fields, since we don't honor height for them
- if (!m_multiLine) {
- currentTextBlockHeight = m_innerText->renderer()->height();
- if (!m_innerBlock && currentTextBlockHeight < m_height)
- m_innerText->renderer()->setPos(m_innerText->renderer()->xPos(), (m_height - currentTextBlockHeight) / 2);
- }
-}
-
-void RenderTextControl::paint(PaintInfo& paintInfo, int tx, int ty)
-{
- RenderBlock::paint(paintInfo, tx, ty);
- if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator)
- theme()->paintCapsLockIndicator(this, paintInfo, absoluteContentBox());
-}
-
-void RenderTextControl::calcPrefWidths()
-{
- ASSERT(prefWidthsDirty());
-
- m_minPrefWidth = 0;
- m_maxPrefWidth = 0;
-
- if (style()->width().isFixed() && style()->width().value() > 0)
- m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
- else {
- int factor;
- int scrollbarSize = 0;
- if (m_multiLine) {
- factor = static_cast<HTMLTextAreaElement*>(node())->cols();
- // FIXME: We should get the size of the scrollbar from the RenderTheme instead.
- if (style()->overflowY() != OHIDDEN)
- scrollbarSize = PlatformScrollbar::verticalScrollbarWidth();
- } else {
- factor = static_cast<HTMLInputElement*>(node())->size();
- if (factor <= 0)
- factor = 20;
- }
-
- // Use average character width. Matches IE.
- int avgCharWidth = style()->font().primaryFont()->avgCharWidth();
- m_maxPrefWidth = (avgCharWidth * factor) + scrollbarSize +
- m_innerText->renderer()->paddingLeft() + m_innerText->renderer()->paddingRight();
-
- // For text inputs, IE adds some extra width.
- if (!m_multiLine)
- m_maxPrefWidth += style()->font().primaryFont()->maxCharWidth() - avgCharWidth;
-
- if (m_resultsButton)
- m_maxPrefWidth += m_resultsButton->renderer()->borderLeft() + m_resultsButton->renderer()->borderRight() +
- m_resultsButton->renderer()->paddingLeft() + m_resultsButton->renderer()->paddingRight();
- if (m_cancelButton)
- m_maxPrefWidth += m_cancelButton->renderer()->borderLeft() + m_cancelButton->renderer()->borderRight() +
- m_cancelButton->renderer()->paddingLeft() + m_cancelButton->renderer()->paddingRight();
- }
-
- if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
- m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
- m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
- } else if (style()->width().isPercent() || (style()->width().isAuto() && style()->height().isPercent()))
- m_minPrefWidth = 0;
- else
- m_minPrefWidth = m_maxPrefWidth;
-
- if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
- m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
- m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
- }
-
- int toAdd = paddingLeft() + paddingRight() + borderLeft() + borderRight();
-
- m_minPrefWidth += toAdd;
- m_maxPrefWidth += toAdd;
-
- setPrefWidthsDirty(false);
-}
-
-void RenderTextControl::forwardEvent(Event* evt)
-{
- if (evt->type() == blurEvent) {
- RenderObject* innerRenderer = m_innerText->renderer();
- if (innerRenderer) {
- RenderLayer* innerLayer = innerRenderer->layer();
- if (innerLayer && !m_multiLine)
- innerLayer->scrollToOffset(style()->direction() == RTL ? innerLayer->scrollWidth() : 0, 0);
- }
- updatePlaceholder();
- capsLockStateMayHaveChanged();
- } else if (evt->type() == focusEvent) {
- updatePlaceholder();
- capsLockStateMayHaveChanged();
- } else {
- if (evt->isMouseEvent() && m_resultsButton && static_cast<MouseEvent*>(evt)->x() < m_innerText->renderer()->absoluteBoundingBoxRect().x())
- m_resultsButton->defaultEventHandler(evt);
- else if (evt->isMouseEvent() && m_cancelButton && static_cast<MouseEvent*>(evt)->x() > m_innerText->renderer()->absoluteBoundingBoxRect().right())
- m_cancelButton->defaultEventHandler(evt);
- else
- m_innerText->defaultEventHandler(evt);
- }
-}
-
-void RenderTextControl::selectionChanged(bool userTriggered)
-{
- HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(node());
- if (m_multiLine)
- static_cast<HTMLTextAreaElement*>(element)->cacheSelection(selectionStart(), selectionEnd());
- else
- static_cast<HTMLInputElement*>(element)->cacheSelection(selectionStart(), selectionEnd());
- if (Frame* frame = document()->frame())
- if (frame->selection()->isRange() && userTriggered)
- element->dispatchHTMLEvent(selectEvent, true, false);
-}
-
-void RenderTextControl::autoscroll()
-{
- if (m_multiLine) {
- layer()->autoscroll();
- } else {
- RenderLayer* layer = m_innerText->renderer()->layer();
- if (layer)
- layer->autoscroll();
- }
-}
-
-int RenderTextControl::scrollWidth() const
-{
- if (!m_multiLine && m_innerText)
- return m_innerText->scrollWidth();
- return RenderBlock::scrollWidth();
-}
-
-int RenderTextControl::scrollHeight() const
-{
- if (m_innerText) {
- if (m_multiLine) {
- // This matches IEs behavior of giving the height of the innerText block
- // as the scrollHeight.
- return m_innerText->scrollHeight() + paddingTop() + paddingBottom();
- } else {
- return m_innerText->scrollHeight();
- }
- }
- return RenderBlock::scrollHeight();
-}
-
-int RenderTextControl::scrollLeft() const
-{
- if (!m_multiLine && m_innerText)
- return m_innerText->scrollLeft();
- return RenderBlock::scrollLeft();
-}
-
-int RenderTextControl::scrollTop() const
-{
- if (!m_multiLine && m_innerText)
- return m_innerText->scrollTop();
- return RenderBlock::scrollTop();
-}
-
-void RenderTextControl::setScrollLeft(int newLeft)
-{
- if (m_multiLine) {
- RenderBlock::setScrollLeft(newLeft);
- } else if (m_innerText) {
- m_innerText->setScrollLeft(newLeft);
- }
-}
-
-void RenderTextControl::setScrollTop(int newTop)
-{
- if (m_multiLine) {
- RenderBlock::setScrollTop(newTop);
- } else if (m_innerText) {
- m_innerText->setScrollTop(newTop);
- }
-}
-
-const AtomicString& RenderTextControl::autosaveName() const
-{
- return static_cast<Element*>(node())->getAttribute(autosaveAttr);
-}
-
-void RenderTextControl::addSearchResult()
-{
- ASSERT(!m_multiLine);
-
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
- if (input->maxResults() <= 0)
- return;
-
- String value = input->value();
- if (value.isEmpty())
- return;
-
- Settings* settings = document()->settings();
- if (!settings || settings->privateBrowsingEnabled())
- return;
-
- int size = static_cast<int>(m_recentSearches.size());
- for (int i = size - 1; i >= 0; --i)
- if (m_recentSearches[i] == value)
- m_recentSearches.remove(i);
-
- m_recentSearches.insert(0, value);
- while (static_cast<int>(m_recentSearches.size()) > input->maxResults())
- m_recentSearches.removeLast();
-
- const AtomicString& name = autosaveName();
- if (!m_searchPopup)
- m_searchPopup = SearchPopupMenu::create(this);
- m_searchPopup->saveRecentSearches(name, m_recentSearches);
-}
-
-void RenderTextControl::showPopup()
-{
- if (m_searchPopupIsVisible)
- return;
-
- if (!m_searchPopup)
- m_searchPopup = SearchPopupMenu::create(this);
-
- if (!m_searchPopup->enabled())
- return;
-
- m_searchPopupIsVisible = true;
-
- const AtomicString& name = autosaveName();
- m_searchPopup->loadRecentSearches(name, m_recentSearches);
-
- // Trim the recent searches list if the maximum size has changed since we last saved.
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
- if (static_cast<int>(m_recentSearches.size()) > input->maxResults()) {
- do
- m_recentSearches.removeLast();
- while (static_cast<int>(m_recentSearches.size()) > input->maxResults());
- m_searchPopup->saveRecentSearches(name, m_recentSearches);
- }
-
- m_searchPopup->show(absoluteBoundingBoxRect(), document()->view(), -1);
-}
-
-void RenderTextControl::hidePopup()
-{
- if (m_searchPopup)
- m_searchPopup->hide();
- m_searchPopupIsVisible = false;
-}
-
-void RenderTextControl::valueChanged(unsigned listIndex, bool fireEvents)
-{
- ASSERT(static_cast<int>(listIndex) < listSize());
- HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
- if (static_cast<int>(listIndex) == (listSize() - 1)) {
- if (fireEvents) {
- m_recentSearches.clear();
- const AtomicString& name = autosaveName();
- if (!name.isEmpty()) {
- if (!m_searchPopup)
- m_searchPopup = SearchPopupMenu::create(this);
- m_searchPopup->saveRecentSearches(name, m_recentSearches);
- }
- }
- } else {
- input->setValue(itemText(listIndex));
- if (fireEvents)
- input->onSearch();
- input->select();
- }
-}
-
-String RenderTextControl::itemText(unsigned listIndex) const
-{
- int size = listSize();
- if (size == 1) {
- ASSERT(!listIndex);
- return searchMenuNoRecentSearchesText();
- }
- if (!listIndex)
- return searchMenuRecentSearchesText();
- if (itemIsSeparator(listIndex))
- return String();
- if (static_cast<int>(listIndex) == (size - 1))
- return searchMenuClearRecentSearchesText();
- return m_recentSearches[listIndex - 1];
-}
-
-bool RenderTextControl::itemIsEnabled(unsigned listIndex) const
-{
- if (!listIndex || itemIsSeparator(listIndex))
- return false;
- return true;
-}
-
-RenderStyle* RenderTextControl::itemStyle(unsigned listIndex) const
-{
- return style();
-}
-
-Color RenderTextControl::itemBackgroundColor(unsigned listIndex) const
-{
- return style()->backgroundColor();
-}
-
-RenderStyle* RenderTextControl::clientStyle() const
-{
- return style();
-}
-
-Document* RenderTextControl::clientDocument() const
-{
- return document();
-}
-
-int RenderTextControl::clientInsetLeft() const
-{
- // Inset the menu by the radius of the cap on the left so that
- // it only runs along the straight part of the bezel.
- return height() / 2;
-}
-
-int RenderTextControl::clientInsetRight() const
-{
- // Inset the menu by the radius of the cap on the right so that
- // it only runs along the straight part of the bezel (unless it needs
- // to be wider).
- return height() / 2;
-}
-
-int RenderTextControl::clientPaddingLeft() const
-{
- return paddingLeft() + m_resultsButton->renderer()->width();
-}
-
-int RenderTextControl::clientPaddingRight() const
-{
- return paddingRight() + m_cancelButton->renderer()->width();
-}
-
-int RenderTextControl::listSize() const
-{
- // If there are no recent searches, then our menu will have 1 "No recent searches" item.
- if (!m_recentSearches.size())
- return 1;
- // Otherwise, leave room in the menu for a header, a separator, and the "Clear recent searches" item.
- return m_recentSearches.size() + 3;
-}
-
-int RenderTextControl::selectedIndex() const
-{
- return -1;
-}
-
-bool RenderTextControl::itemIsSeparator(unsigned listIndex) const
-{
- // The separator will be the second to last item in our list.
- return static_cast<int>(listIndex) == (listSize() - 2);
-}
-
-bool RenderTextControl::itemIsLabel(unsigned listIndex) const
-{
- return listIndex == 0;
-}
-
-bool RenderTextControl::itemIsSelected(unsigned listIndex) const
-{
- return false;
-}
-
-void RenderTextControl::setTextFromItem(unsigned listIndex)
-{
- static_cast<HTMLInputElement*>(node())->setValue(itemText(listIndex));
-}
-
-bool RenderTextControl::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
-{
- RenderLayer* layer = m_innerText->renderer()->layer();
- if (!m_multiLine && layer && layer->scroll(direction, granularity, multiplier))
- return true;
- return RenderObject::scroll(direction, granularity, multiplier);
-}
-
-void RenderTextControl::searchEventTimerFired(Timer<RenderTextControl>*)
-{
- static_cast<HTMLInputElement*>(node())->onSearch();
-}
-
-void RenderTextControl::stopSearchEventTimer()
-{
- m_searchEventTimer.stop();
-}
-
-void RenderTextControl::startSearchEventTimer()
-{
- unsigned length = text().length();
-
- // If there's no text, fire the event right away.
- if (!length) {
- m_searchEventTimer.stop();
- static_cast<HTMLInputElement*>(node())->onSearch();
- return;
- }
-
- // After typing the first key, we wait 0.5 seconds.
- // After the second key, 0.4 seconds, then 0.3, then 0.2 from then on.
- m_searchEventTimer.startOneShot(max(0.2, 0.6 - 0.1 * length));
-}
-
-bool RenderTextControl::isScrollable() const
-{
- if (!m_multiLine && m_innerText && m_innerText->renderer()->isScrollable())
- return true;
- return RenderObject::isScrollable();
-}
-
-FontSelector* RenderTextControl::fontSelector() const
-{
- return document()->styleSelector()->fontSelector();
-}
-
-void RenderTextControl::capsLockStateMayHaveChanged()
-{
- // Only draw the caps lock indicator if these things are true:
- // 1) The field is a password field
- // 2) The frame is active
- // 3) The element is focused
- // 4) The caps lock is on
-
- bool shouldDrawCapsLockIndicator = false;
- if (Node* n = node())
- if (Document* d = document())
- if (Frame* f = d->frame())
- shouldDrawCapsLockIndicator = !m_multiLine && static_cast<HTMLInputElement*>(n)->inputType() == HTMLInputElement::PASSWORD &&
- f->selection()->isFocusedAndActive() && d->focusedNode() == n && PlatformKeyboardEvent::currentCapsLockState();
-
- if (shouldDrawCapsLockIndicator != m_shouldDrawCapsLockIndicator) {
- m_shouldDrawCapsLockIndicator = shouldDrawCapsLockIndicator;
- repaint();
- }
-}
-
-} // namespace WebCore
diff --git a/webkit/pending/Selection.cpp b/webkit/pending/Selection.cpp
deleted file mode 100644
index 478dd5a..0000000
--- a/webkit/pending/Selection.cpp
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Selection.h"
-
-#include "CString.h"
-#include "Document.h"
-#include "Element.h"
-#include "htmlediting.h"
-#include "VisiblePosition.h"
-#include "visible_units.h"
-#include "Range.h"
-#include <unicode/ubrk.h>
-#include <wtf/Assertions.h>
-#include <stdio.h>
-
-namespace WebCore {
-
-Selection::Selection()
- : m_affinity(DOWNSTREAM)
- , m_granularity(CharacterGranularity)
- , m_state(NONE)
- , m_baseIsFirst(true)
-{
-}
-
-Selection::Selection(const Position& pos, EAffinity affinity)
- : m_base(pos)
- , m_extent(pos)
- , m_affinity(affinity)
- , m_granularity(CharacterGranularity)
-{
- validate();
-}
-
-Selection::Selection(const Position& base, const Position& extent, EAffinity affinity)
- : m_base(base)
- , m_extent(extent)
- , m_affinity(affinity)
- , m_granularity(CharacterGranularity)
-{
- validate();
-}
-
-Selection::Selection(const VisiblePosition& pos)
- : m_base(pos.deepEquivalent())
- , m_extent(pos.deepEquivalent())
- , m_affinity(pos.affinity())
- , m_granularity(CharacterGranularity)
-{
- validate();
-}
-
-Selection::Selection(const VisiblePosition& base, const VisiblePosition& extent)
- : m_base(base.deepEquivalent())
- , m_extent(extent.deepEquivalent())
- , m_affinity(base.affinity())
- , m_granularity(CharacterGranularity)
-{
- validate();
-}
-
-Selection::Selection(const Range* range, EAffinity affinity)
- : m_base(range->startPosition())
- , m_extent(range->endPosition())
- , m_affinity(affinity)
- , m_granularity(CharacterGranularity)
-{
- validate();
-}
-
-Selection Selection::selectionFromContentsOfNode(Node* node)
-{
- return Selection(Position(node, 0), Position(node, maxDeepOffset(node)), DOWNSTREAM);
-}
-
-void Selection::setBase(const Position& position)
-{
- m_base = position;
- validate();
-}
-
-void Selection::setBase(const VisiblePosition& visiblePosition)
-{
- m_base = visiblePosition.deepEquivalent();
- validate();
-}
-
-void Selection::setExtent(const Position& position)
-{
- m_extent = position;
- validate();
-}
-
-void Selection::setExtent(const VisiblePosition& visiblePosition)
-{
- m_extent = visiblePosition.deepEquivalent();
- validate();
-}
-
-PassRefPtr<Range> Selection::toRange() const
-{
- if (isNone())
- return 0;
-
- // Make sure we have an updated layout since this function is called
- // in the course of running edit commands which modify the DOM.
- // Failing to call this can result in equivalentXXXPosition calls returning
- // incorrect results.
- m_start.node()->document()->updateLayout();
-
- // Check again, because updating layout can clear the selection.
- if (isNone())
- return 0;
-
- Position s, e;
- if (isCaret()) {
- // If the selection is a caret, move the range start upstream. This helps us match
- // the conventions of text editors tested, which make style determinations based
- // on the character before the caret, if any.
- s = rangeCompliantEquivalent(m_start.upstream());
- e = s;
- } else {
- // If the selection is a range, select the minimum range that encompasses the selection.
- // Again, this is to match the conventions of text editors tested, which make style
- // determinations based on the first character of the selection.
- // For instance, this operation helps to make sure that the "X" selected below is the
- // only thing selected. The range should not be allowed to "leak" out to the end of the
- // previous text node, or to the beginning of the next text node, each of which has a
- // different style.
- //
- // On a treasure map, <b>X</b> marks the spot.
- // ^ selected
- //
- ASSERT(isRange());
- s = m_start.downstream();
- e = m_end.upstream();
- if (Range::compareBoundaryPoints(s.node(), s.offset(), e.node(), e.offset()) > 0) {
- // Make sure the start is before the end.
- // The end can wind up before the start if collapsed whitespace is the only thing selected.
- Position tmp = s;
- s = e;
- e = tmp;
- }
- s = rangeCompliantEquivalent(s);
- e = rangeCompliantEquivalent(e);
- }
-
- ExceptionCode ec = 0;
- RefPtr<Range> result(Range::create(s.node()->document()));
- result->setStart(s.node(), s.offset(), ec);
- if (ec) {
- LOG_ERROR("Exception setting Range start from Selection: %d", ec);
- return 0;
- }
- result->setEnd(e.node(), e.offset(), ec);
- if (ec) {
- LOG_ERROR("Exception setting Range end from Selection: %d", ec);
- return 0;
- }
- return result.release();
-}
-
-bool Selection::expandUsingGranularity(TextGranularity granularity)
-{
- if (isNone())
- return false;
-
- m_granularity = granularity;
- validate();
- return true;
-}
-
-void Selection::validate()
-{
- // Move the selection to rendered positions, if possible.
- bool baseAndExtentEqual = m_base == m_extent;
- if (m_base.isNotNull()) {
- m_base = VisiblePosition(m_base, m_affinity).deepEquivalent();
- if (baseAndExtentEqual)
- m_extent = m_base;
- }
- if (m_extent.isNotNull() && !baseAndExtentEqual)
- m_extent = VisiblePosition(m_extent, m_affinity).deepEquivalent();
-
- // Make sure we do not have a dangling base or extent.
- if (m_base.isNull() && m_extent.isNull())
- m_baseIsFirst = true;
- else if (m_base.isNull()) {
- m_base = m_extent;
- m_baseIsFirst = true;
- } else if (m_extent.isNull()) {
- m_extent = m_base;
- m_baseIsFirst = true;
- } else {
- m_baseIsFirst = comparePositions(m_base, m_extent) <= 0;
- }
-
- if (m_baseIsFirst) {
- m_start = m_base;
- m_end = m_extent;
- } else {
- m_start = m_extent;
- m_end = m_base;
- }
-
- // Expand the selection if requested.
- switch (m_granularity) {
- case CharacterGranularity:
- // Don't do any expansion.
- break;
- case WordGranularity: {
- // General case: Select the word the caret is positioned inside of, or at the start of (RightWordIfOnBoundary).
- // Edge case: If the caret is after the last word in a soft-wrapped line or the last word in
- // the document, select that last word (LeftWordIfOnBoundary).
- // Edge case: If the caret is after the last word in a paragraph, select from the the end of the
- // last word to the line break (also RightWordIfOnBoundary);
- VisiblePosition start = VisiblePosition(m_start, m_affinity);
- VisiblePosition originalEnd(m_end, m_affinity);
- EWordSide side = RightWordIfOnBoundary;
- if (isEndOfDocument(start) || (isEndOfLine(start) && !isStartOfLine(start) && !isEndOfParagraph(start)))
- side = LeftWordIfOnBoundary;
- m_start = startOfWord(start, side).deepEquivalent();
- side = RightWordIfOnBoundary;
- if (isEndOfDocument(originalEnd) || (isEndOfLine(originalEnd) && !isStartOfLine(originalEnd) && !isEndOfParagraph(originalEnd)))
- side = LeftWordIfOnBoundary;
-
- VisiblePosition wordEnd(endOfWord(originalEnd, side));
- VisiblePosition end(wordEnd);
-
- if (isEndOfParagraph(originalEnd)) {
- // Select the paragraph break (the space from the end of a paragraph to the start of
- // the next one) to match TextEdit.
- end = wordEnd.next();
-
- if (Node* table = isFirstPositionAfterTable(end)) {
- // The paragraph break after the last paragraph in the last cell of a block table ends
- // at the start of the paragraph after the table.
- if (isBlock(table))
- end = end.next(true);
- else
- end = wordEnd;
- }
-
- if (end.isNull())
- end = wordEnd;
-
- }
-
-#if PLATFORM(WIN_OS)
- // Windows platform requires us to select trailing whitespace after selecting words.
- while (u_isblank(end.characterAfter())) {
- end = end.next();
- }
- if (end.isNull())
- end = wordEnd;
-#endif
-
- m_end = end.deepEquivalent();
- break;
- }
- case SentenceGranularity: {
- m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent();
- m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
- break;
- }
- case LineGranularity: {
- m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent();
- VisiblePosition end = endOfLine(VisiblePosition(m_end, m_affinity));
- // If the end of this line is at the end of a paragraph, include the space
- // after the end of the line in the selection.
- if (isEndOfParagraph(end)) {
- VisiblePosition next = end.next();
- if (next.isNotNull())
- end = next;
- }
- m_end = end.deepEquivalent();
- break;
- }
- case LineBoundary:
- m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent();
- m_end = endOfLine(VisiblePosition(m_end, m_affinity)).deepEquivalent();
- break;
- case ParagraphGranularity: {
- VisiblePosition pos(m_start, m_affinity);
- if (isStartOfLine(pos) && isEndOfDocument(pos))
- pos = pos.previous();
- m_start = startOfParagraph(pos).deepEquivalent();
- VisiblePosition visibleParagraphEnd = endOfParagraph(VisiblePosition(m_end, m_affinity));
-
- // Include the "paragraph break" (the space from the end of this paragraph to the start
- // of the next one) in the selection.
- VisiblePosition end(visibleParagraphEnd.next());
-
- if (Node* table = isFirstPositionAfterTable(end)) {
- // The paragraph break after the last paragraph in the last cell of a block table ends
- // at the start of the paragraph after the table, not at the position just after the table.
- if (isBlock(table))
- end = end.next(true);
- // There is no parargraph break after the last paragraph in the last cell of an inline table.
- else
- end = visibleParagraphEnd;
- }
-
- if (end.isNull())
- end = visibleParagraphEnd;
-
- m_end = end.deepEquivalent();
- break;
- }
- case DocumentBoundary:
- m_start = startOfDocument(VisiblePosition(m_start, m_affinity)).deepEquivalent();
- m_end = endOfDocument(VisiblePosition(m_end, m_affinity)).deepEquivalent();
- break;
- case ParagraphBoundary:
- m_start = startOfParagraph(VisiblePosition(m_start, m_affinity)).deepEquivalent();
- m_end = endOfParagraph(VisiblePosition(m_end, m_affinity)).deepEquivalent();
- break;
- case SentenceBoundary:
- m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent();
- m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
- break;
- }
-
- // Make sure we do not have a dangling start or end.
- if (m_start.isNull())
- m_start = m_end;
- if (m_end.isNull())
- m_end = m_start;
-
- adjustForEditableContent();
-
- // adjust the state
- if (m_start.isNull()) {
- ASSERT(m_end.isNull());
- m_state = NONE;
-
- // enforce downstream affinity if not caret, as affinity only
- // makes sense for caret
- m_affinity = DOWNSTREAM;
- } else if (m_start == m_end || m_start.upstream() == m_end.upstream()) {
- m_state = CARET;
- } else {
- m_state = RANGE;
-
- // enforce downstream affinity if not caret, as affinity only
- // makes sense for caret
- m_affinity = DOWNSTREAM;
-
- // "Constrain" the selection to be the smallest equivalent range of nodes.
- // This is a somewhat arbitrary choice, but experience shows that it is
- // useful to make to make the selection "canonical" (if only for
- // purposes of comparing selections). This is an ideal point of the code
- // to do this operation, since all selection changes that result in a RANGE
- // come through here before anyone uses it.
- // FIXME: Canonicalizing is good, but haven't we already done it (when we
- // set these two positions to VisiblePosition deepEquivalent()s above)?
- m_start = m_start.downstream();
- m_end = m_end.upstream();
- }
-}
-
-// FIXME: This function breaks the invariant of this class.
-// But because we use Selection to store values in editing commands for use when
-// undoing the command, we need to be able to create a selection that while currently
-// invalid, will be valid once the changes are undone. This is a design problem.
-// To fix it we either need to change the invariants of Selection or create a new
-// class for editing to use that can manipulate selections that are not currently valid.
-void Selection::setWithoutValidation(const Position& base, const Position& extent)
-{
- ASSERT(!base.isNull());
- ASSERT(!extent.isNull());
- ASSERT(base != extent);
- ASSERT(m_affinity == DOWNSTREAM);
- ASSERT(m_granularity == CharacterGranularity);
- m_base = base;
- m_extent = extent;
- m_baseIsFirst = comparePositions(base, extent) <= 0;
- if (m_baseIsFirst) {
- m_start = base;
- m_end = extent;
- } else {
- m_start = extent;
- m_end = base;
- }
- m_state = RANGE;
-}
-
-void Selection::adjustForEditableContent()
-{
- if (m_base.isNull() || m_start.isNull() || m_end.isNull())
- return;
-
- Node* baseRoot = highestEditableRoot(m_base);
- Node* startRoot = highestEditableRoot(m_start);
- Node* endRoot = highestEditableRoot(m_end);
-
- Node* baseEditableAncestor = lowestEditableAncestor(m_base.node());
-
- // The base, start and end are all in the same region. No adjustment necessary.
- if (baseRoot == startRoot && baseRoot == endRoot)
- return;
-
- // The selection is based in editable content.
- if (baseRoot) {
- // If the start is outside the base's editable root, cap it at the start of that root.
- // If the start is in non-editable content that is inside the base's editable root, put it
- // at the first editable position after start inside the base's editable root.
- if (startRoot != baseRoot) {
- VisiblePosition first = firstEditablePositionAfterPositionInRoot(m_start, baseRoot);
- m_start = first.deepEquivalent();
- if (m_start.isNull()) {
- ASSERT_NOT_REACHED();
- m_start = m_end;
- }
- }
- // If the end is outside the base's editable root, cap it at the end of that root.
- // If the end is in non-editable content that is inside the base's root, put it
- // at the last editable position before the end inside the base's root.
- if (endRoot != baseRoot) {
- VisiblePosition last = lastEditablePositionBeforePositionInRoot(m_end, baseRoot);
- m_end = last.deepEquivalent();
- if (m_end.isNull()) {
- ASSERT_NOT_REACHED();
- m_end = m_start;
- }
- }
- // The selection is based in non-editable content.
- } else {
- // FIXME: Non-editable pieces inside editable content should be atomic, in the same way that editable
- // pieces in non-editable content are atomic.
-
- // The selection ends in editable content or non-editable content inside a different editable ancestor,
- // move backward until non-editable content inside the same lowest editable ancestor is reached.
- Node* endEditableAncestor = lowestEditableAncestor(m_end.node());
- if (endRoot || endEditableAncestor != baseEditableAncestor) {
-
- Position p = previousVisuallyDistinctCandidate(m_end);
- Node* shadowAncestor = endRoot ? endRoot->shadowAncestorNode() : 0;
- if (p.isNull() && endRoot && (shadowAncestor != endRoot))
- p = Position(shadowAncestor, maxDeepOffset(shadowAncestor));
- while (p.isNotNull() && !(lowestEditableAncestor(p.node()) == baseEditableAncestor && !isEditablePosition(p))) {
- Node* root = editableRootForPosition(p);
- shadowAncestor = root ? root->shadowAncestorNode() : 0;
- p = isAtomicNode(p.node()) ? positionBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
- if (p.isNull() && (shadowAncestor != root))
- p = Position(shadowAncestor, maxDeepOffset(shadowAncestor));
- }
- VisiblePosition previous(p);
-
- if (previous.isNull()) {
- ASSERT_NOT_REACHED();
- m_base = Position();
- m_extent = Position();
- validate();
- return;
- }
- m_end = previous.deepEquivalent();
- }
-
- // The selection starts in editable content or non-editable content inside a different editable ancestor,
- // move forward until non-editable content inside the same lowest editable ancestor is reached.
- Node* startEditableAncestor = lowestEditableAncestor(m_start.node());
- if (startRoot || startEditableAncestor != baseEditableAncestor) {
- Position p = nextVisuallyDistinctCandidate(m_start);
- Node* shadowAncestor = startRoot ? startRoot->shadowAncestorNode() : 0;
- if (p.isNull() && startRoot && (shadowAncestor != startRoot))
- p = Position(shadowAncestor, 0);
- while (p.isNotNull() && !(lowestEditableAncestor(p.node()) == baseEditableAncestor && !isEditablePosition(p))) {
- Node* root = editableRootForPosition(p);
- shadowAncestor = root ? root->shadowAncestorNode() : 0;
- p = isAtomicNode(p.node()) ? positionAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
- if (p.isNull() && (shadowAncestor != root))
- p = Position(shadowAncestor, 0);
- }
- VisiblePosition next(p);
-
- if (next.isNull()) {
- ASSERT_NOT_REACHED();
- m_base = Position();
- m_extent = Position();
- validate();
- return;
- }
- m_start = next.deepEquivalent();
- }
- }
-
- // Correct the extent if necessary.
- if (baseEditableAncestor != lowestEditableAncestor(m_extent.node()))
- m_extent = m_baseIsFirst ? m_end : m_start;
-}
-
-bool Selection::isContentEditable() const
-{
- return isEditablePosition(start());
-}
-
-bool Selection::isContentRichlyEditable() const
-{
- return isRichlyEditablePosition(start());
-}
-
-Element* Selection::rootEditableElement() const
-{
- return editableRootForPosition(start());
-}
-
-Node* Selection::shadowTreeRootNode() const
-{
- return start().node() ? start().node()->shadowTreeRootNode() : 0;
-}
-
-void Selection::debugPosition() const
-{
- if (!m_start.node())
- return;
-
- fprintf(stderr, "Selection =================\n");
-
- if (m_start == m_end) {
- Position pos = m_start;
- fprintf(stderr, "pos: %s %p:%d\n", pos.node()->nodeName().utf8().data(), pos.node(), pos.offset());
- } else {
- Position pos = m_start;
- fprintf(stderr, "start: %s %p:%d\n", pos.node()->nodeName().utf8().data(), pos.node(), pos.offset());
- fprintf(stderr, "-----------------------------------\n");
- pos = m_end;
- fprintf(stderr, "end: %s %p:%d\n", pos.node()->nodeName().utf8().data(), pos.node(), pos.offset());
- fprintf(stderr, "-----------------------------------\n");
- }
-
- fprintf(stderr, "================================\n");
-}
-
-#ifndef NDEBUG
-
-void Selection::formatForDebugger(char* buffer, unsigned length) const
-{
- String result;
- String s;
-
- if (isNone()) {
- result = "<none>";
- } else {
- const int FormatBufferSize = 1024;
- char s[FormatBufferSize];
- result += "from ";
- start().formatForDebugger(s, FormatBufferSize);
- result += s;
- result += " to ";
- end().formatForDebugger(s, FormatBufferSize);
- result += s;
- }
-
- strncpy(buffer, result.utf8().data(), length - 1);
-}
-
-void Selection::showTreeForThis() const
-{
- if (start().node()) {
- start().node()->showTreeAndMark(start().node(), "S", end().node(), "E");
- fprintf(stderr, "start offset: %d, end offset: %d\n", start().offset(), end().offset());
- }
-}
-
-#endif
-
-} // namespace WebCore
-
-#ifndef NDEBUG
-
-void showTree(const WebCore::Selection& sel)
-{
- sel.showTreeForThis();
-}
-
-void showTree(const WebCore::Selection* sel)
-{
- if (sel)
- sel->showTreeForThis();
-}
-
-#endif
diff --git a/webkit/pending/Settings.cpp b/webkit/pending/Settings.cpp
deleted file mode 100644
index 9e7e82a..0000000
--- a/webkit/pending/Settings.cpp
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Settings.h"
-
-#include "Frame.h"
-#include "FrameTree.h"
-#include "Page.h"
-#include "PageCache.h"
-#include "HistoryItem.h"
-
-#if ENABLE(DATABASE)
-#include "DatabaseTracker.h"
-#endif
-
-namespace WebCore {
-
-static void setNeedsReapplyStylesInAllFrames(Page* page)
-{
- for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
- frame->setNeedsReapplyStyles();
-}
-
-Settings::Settings(Page* page)
- : m_page(page)
- , m_editableLinkBehavior(EditableLinkDefaultBehavior)
- , m_minimumFontSize(0)
- , m_minimumLogicalFontSize(0)
- , m_defaultFontSize(0)
- , m_defaultFixedFontSize(0)
- , m_isJavaEnabled(false)
- , m_loadsImagesAutomatically(false)
- , m_privateBrowsingEnabled(false)
- , m_arePluginsEnabled(false)
- , m_isJavaScriptEnabled(false)
- , m_javaScriptCanOpenWindowsAutomatically(false)
- , m_shouldPrintBackgrounds(false)
- , m_textAreasAreResizable(false)
-#if ENABLE(DASHBOARD_SUPPORT)
- , m_usesDashboardBackwardCompatibilityMode(false)
-#endif
- , m_needsAdobeFrameReloadingQuirk(false)
- , m_needsKeyboardEventDisambiguationQuirks(false)
- , m_isDOMPasteAllowed(false)
- , m_shrinksStandaloneImagesToFit(true)
- , m_usesPageCache(false)
- , m_showsURLsInToolTips(false)
- , m_forceFTPDirectoryListings(false)
- , m_developerExtrasEnabled(false)
- , m_authorAndUserStylesEnabled(true)
- , m_needsSiteSpecificQuirks(false)
- , m_fontRenderingMode(0)
- , m_webArchiveDebugModeEnabled(false)
- , m_inApplicationChromeMode(false)
- , m_offlineWebApplicationCacheEnabled(false)
- , m_rangeMutationDisabledForOldAppleMail(false)
- , m_shouldPaintCustomScrollbars(false)
- , m_zoomsTextOnly(false)
- , m_enforceCSSMIMETypeInStrictMode(true)
- , m_usesEncodingDetector(false)
- , m_allow_scripts_to_close_windows(false)
-{
- // A Frame may not have been created yet, so we initialize the AtomicString
- // hash before trying to use it.
- AtomicString::init();
-}
-
-void Settings::setStandardFontFamily(const AtomicString& standardFontFamily)
-{
- if (standardFontFamily == m_standardFontFamily)
- return;
-
- m_standardFontFamily = standardFontFamily;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setFixedFontFamily(const AtomicString& fixedFontFamily)
-{
- if (m_fixedFontFamily == fixedFontFamily)
- return;
-
- m_fixedFontFamily = fixedFontFamily;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setSerifFontFamily(const AtomicString& serifFontFamily)
-{
- if (m_serifFontFamily == serifFontFamily)
- return;
-
- m_serifFontFamily = serifFontFamily;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setSansSerifFontFamily(const AtomicString& sansSerifFontFamily)
-{
- if (m_sansSerifFontFamily == sansSerifFontFamily)
- return;
-
- m_sansSerifFontFamily = sansSerifFontFamily;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setCursiveFontFamily(const AtomicString& cursiveFontFamily)
-{
- if (m_cursiveFontFamily == cursiveFontFamily)
- return;
-
- m_cursiveFontFamily = cursiveFontFamily;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setFantasyFontFamily(const AtomicString& fantasyFontFamily)
-{
- if (m_fantasyFontFamily == fantasyFontFamily)
- return;
-
- m_fantasyFontFamily = fantasyFontFamily;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setMinimumFontSize(int minimumFontSize)
-{
- if (m_minimumFontSize == minimumFontSize)
- return;
-
- m_minimumFontSize = minimumFontSize;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setMinimumLogicalFontSize(int minimumLogicalFontSize)
-{
- if (m_minimumLogicalFontSize == minimumLogicalFontSize)
- return;
-
- m_minimumLogicalFontSize = minimumLogicalFontSize;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setDefaultFontSize(int defaultFontSize)
-{
- if (m_defaultFontSize == defaultFontSize)
- return;
-
- m_defaultFontSize = defaultFontSize;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setDefaultFixedFontSize(int defaultFontSize)
-{
- if (m_defaultFixedFontSize == defaultFontSize)
- return;
-
- m_defaultFixedFontSize = defaultFontSize;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setLoadsImagesAutomatically(bool loadsImagesAutomatically)
-{
- m_loadsImagesAutomatically = loadsImagesAutomatically;
-}
-
-void Settings::setJavaScriptEnabled(bool isJavaScriptEnabled)
-{
- m_isJavaScriptEnabled = isJavaScriptEnabled;
-}
-
-void Settings::setJavaEnabled(bool isJavaEnabled)
-{
- m_isJavaEnabled = isJavaEnabled;
-}
-
-void Settings::setPluginsEnabled(bool arePluginsEnabled)
-{
- m_arePluginsEnabled = arePluginsEnabled;
-}
-
-void Settings::setPrivateBrowsingEnabled(bool privateBrowsingEnabled)
-{
- m_privateBrowsingEnabled = privateBrowsingEnabled;
-}
-
-void Settings::setJavaScriptCanOpenWindowsAutomatically(bool javaScriptCanOpenWindowsAutomatically)
-{
- m_javaScriptCanOpenWindowsAutomatically = javaScriptCanOpenWindowsAutomatically;
-}
-
-void Settings::setDefaultTextEncodingName(const String& defaultTextEncodingName)
-{
- m_defaultTextEncodingName = defaultTextEncodingName;
-}
-
-void Settings::setUserStyleSheetLocation(const KURL& userStyleSheetLocation)
-{
- if (m_userStyleSheetLocation == userStyleSheetLocation)
- return;
-
- m_userStyleSheetLocation = userStyleSheetLocation;
-
- m_page->userStyleSheetLocationChanged();
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setShouldPrintBackgrounds(bool shouldPrintBackgrounds)
-{
- m_shouldPrintBackgrounds = shouldPrintBackgrounds;
-}
-
-void Settings::setTextAreasAreResizable(bool textAreasAreResizable)
-{
- if (m_textAreasAreResizable == textAreasAreResizable)
- return;
-
- m_textAreasAreResizable = textAreasAreResizable;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setEditableLinkBehavior(EditableLinkBehavior editableLinkBehavior)
-{
- m_editableLinkBehavior = editableLinkBehavior;
-}
-
-#if ENABLE(DASHBOARD_SUPPORT)
-void Settings::setUsesDashboardBackwardCompatibilityMode(bool usesDashboardBackwardCompatibilityMode)
-{
- m_usesDashboardBackwardCompatibilityMode = usesDashboardBackwardCompatibilityMode;
-}
-#endif
-
-// FIXME: This quirk is needed because of Radar 4674537 and 5211271. We need to phase it out once Adobe
-// can fix the bug from their end.
-void Settings::setNeedsAdobeFrameReloadingQuirk(bool shouldNotReloadIFramesForUnchangedSRC)
-{
- m_needsAdobeFrameReloadingQuirk = shouldNotReloadIFramesForUnchangedSRC;
-}
-
-// This is a quirk we are pro-actively applying to old applications. It changes keyboard event dispatching,
-// making keyIdentifier available on keypress events, making charCode available on keydown/keyup events,
-// and getting keypress dispatched in more cases.
-void Settings::setNeedsKeyboardEventDisambiguationQuirks(bool needsQuirks)
-{
- m_needsKeyboardEventDisambiguationQuirks = needsQuirks;
-}
-
-void Settings::setDOMPasteAllowed(bool DOMPasteAllowed)
-{
- m_isDOMPasteAllowed = DOMPasteAllowed;
-}
-
-void Settings::setUsesPageCache(bool usesPageCache)
-{
- if (m_usesPageCache == usesPageCache)
- return;
-
- m_usesPageCache = usesPageCache;
- if (!m_usesPageCache) {
- HistoryItemVector& historyItems = m_page->backForwardList()->entries();
- for (unsigned i = 0; i < historyItems.size(); i++)
- pageCache()->remove(historyItems[i].get());
- pageCache()->releaseAutoreleasedPagesNow();
- }
-}
-
-void Settings::setShrinksStandaloneImagesToFit(bool shrinksStandaloneImagesToFit)
-{
- m_shrinksStandaloneImagesToFit = shrinksStandaloneImagesToFit;
-}
-
-void Settings::setShowsURLsInToolTips(bool showsURLsInToolTips)
-{
- m_showsURLsInToolTips = showsURLsInToolTips;
-}
-
-void Settings::setFTPDirectoryTemplatePath(const String& path)
-{
- m_ftpDirectoryTemplatePath = path;
-}
-
-void Settings::setForceFTPDirectoryListings(bool force)
-{
- m_forceFTPDirectoryListings = force;
-}
-
-void Settings::setDeveloperExtrasEnabled(bool developerExtrasEnabled)
-{
- m_developerExtrasEnabled = developerExtrasEnabled;
-}
-
-void Settings::setAuthorAndUserStylesEnabled(bool authorAndUserStylesEnabled)
-{
- if (m_authorAndUserStylesEnabled == authorAndUserStylesEnabled)
- return;
-
- m_authorAndUserStylesEnabled = authorAndUserStylesEnabled;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setFontRenderingMode(FontRenderingMode mode)
-{
- if (fontRenderingMode() == mode)
- return;
- m_fontRenderingMode = mode;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-FontRenderingMode Settings::fontRenderingMode() const
-{
- return static_cast<FontRenderingMode>(m_fontRenderingMode);
-}
-
-void Settings::setNeedsSiteSpecificQuirks(bool needsQuirks)
-{
- m_needsSiteSpecificQuirks = needsQuirks;
-}
-
-void Settings::setWebArchiveDebugModeEnabled(bool enabled)
-{
- m_webArchiveDebugModeEnabled = enabled;
-}
-
-void Settings::setLocalStorageDatabasePath(const String& path)
-{
- m_localStorageDatabasePath = path;
-}
-
-void Settings::disableRangeMutationForOldAppleMail(bool disable)
-{
- m_rangeMutationDisabledForOldAppleMail = disable;
-}
-
-void Settings::setApplicationChromeMode(bool mode)
-{
- m_inApplicationChromeMode = mode;
-}
-
-void Settings::setOfflineWebApplicationCacheEnabled(bool enabled)
-{
- m_offlineWebApplicationCacheEnabled = enabled;
-}
-
-void Settings::setShouldPaintCustomScrollbars(bool shouldPaintCustomScrollbars)
-{
- m_shouldPaintCustomScrollbars = shouldPaintCustomScrollbars;
-}
-
-void Settings::setZoomsTextOnly(bool zoomsTextOnly)
-{
- if (zoomsTextOnly == m_zoomsTextOnly)
- return;
-
- m_zoomsTextOnly = zoomsTextOnly;
- setNeedsReapplyStylesInAllFrames(m_page);
-}
-
-void Settings::setEnforceCSSMIMETypeInStrictMode(bool enforceCSSMIMETypeInStrictMode)
-{
- m_enforceCSSMIMETypeInStrictMode = enforceCSSMIMETypeInStrictMode;
-}
-
-void Settings::setUsesUniversalDetector(bool usesEncodingDetector)
-{
- m_usesEncodingDetector = usesEncodingDetector;
-}
-
-void Settings::setAllowScriptsToCloseWindows(bool allow_scripts_to_close_windows)
-{
- m_allow_scripts_to_close_windows = allow_scripts_to_close_windows;
-}
-
-} // namespace WebCore
diff --git a/webkit/pending/Settings.h b/webkit/pending/Settings.h
deleted file mode 100644
index 0d12520..0000000
--- a/webkit/pending/Settings.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2003, 2006, 2007, 2008 Apple Inc. All rights reserved.
- * (C) 2006 Graham Dennis (graham.dennis@gmail.com)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef Settings_h
-#define Settings_h
-
-#include "AtomicString.h"
-#include "FontDescription.h"
-#include "KURL.h"
-
-namespace WebCore {
-
- class Page;
-
- enum EditableLinkBehavior {
- EditableLinkDefaultBehavior = 0,
- EditableLinkAlwaysLive,
- EditableLinkOnlyLiveWithShiftKey,
- EditableLinkLiveWhenNotFocused,
- EditableLinkNeverLive
- };
-
- class Settings {
- public:
- Settings(Page*);
-
- void setStandardFontFamily(const AtomicString&);
- const AtomicString& standardFontFamily() const { return m_standardFontFamily; }
-
- void setFixedFontFamily(const AtomicString&);
- const AtomicString& fixedFontFamily() const { return m_fixedFontFamily; }
-
- void setSerifFontFamily(const AtomicString&);
- const AtomicString& serifFontFamily() const { return m_serifFontFamily; }
-
- void setSansSerifFontFamily(const AtomicString&);
- const AtomicString& sansSerifFontFamily() const { return m_sansSerifFontFamily; }
-
- void setCursiveFontFamily(const AtomicString&);
- const AtomicString& cursiveFontFamily() const { return m_cursiveFontFamily; }
-
- void setFantasyFontFamily(const AtomicString&);
- const AtomicString& fantasyFontFamily() const { return m_fantasyFontFamily; }
-
- void setMinimumFontSize(int);
- int minimumFontSize() const { return m_minimumFontSize; }
-
- void setMinimumLogicalFontSize(int);
- int minimumLogicalFontSize() const { return m_minimumLogicalFontSize; }
-
- void setDefaultFontSize(int);
- int defaultFontSize() const { return m_defaultFontSize; }
-
- void setDefaultFixedFontSize(int);
- int defaultFixedFontSize() const { return m_defaultFixedFontSize; }
-
- void setLoadsImagesAutomatically(bool);
- bool loadsImagesAutomatically() const { return m_loadsImagesAutomatically; }
-
- void setJavaScriptEnabled(bool);
- bool isJavaScriptEnabled() const { return m_isJavaScriptEnabled; }
-
- void setJavaScriptCanOpenWindowsAutomatically(bool);
- bool JavaScriptCanOpenWindowsAutomatically() const { return m_javaScriptCanOpenWindowsAutomatically; }
-
- void setJavaEnabled(bool);
- bool isJavaEnabled() const { return m_isJavaEnabled; }
-
- void setPluginsEnabled(bool);
- bool arePluginsEnabled() const { return m_arePluginsEnabled; }
-
- void setPrivateBrowsingEnabled(bool);
- bool privateBrowsingEnabled() const { return m_privateBrowsingEnabled; }
-
- void setDefaultTextEncodingName(const String&);
- const String& defaultTextEncodingName() const { return m_defaultTextEncodingName; }
-
- void setUserStyleSheetLocation(const KURL&);
- const KURL& userStyleSheetLocation() const { return m_userStyleSheetLocation; }
-
- void setShouldPrintBackgrounds(bool);
- bool shouldPrintBackgrounds() const { return m_shouldPrintBackgrounds; }
-
- void setTextAreasAreResizable(bool);
- bool textAreasAreResizable() const { return m_textAreasAreResizable; }
-
- void setEditableLinkBehavior(EditableLinkBehavior);
- EditableLinkBehavior editableLinkBehavior() const { return m_editableLinkBehavior; }
-
-#if ENABLE(DASHBOARD_SUPPORT)
- void setUsesDashboardBackwardCompatibilityMode(bool);
- bool usesDashboardBackwardCompatibilityMode() const { return m_usesDashboardBackwardCompatibilityMode; }
-#endif
-
- void setNeedsAdobeFrameReloadingQuirk(bool);
- bool needsAcrobatFrameReloadingQuirk() const { return m_needsAdobeFrameReloadingQuirk; }
-
- void setNeedsKeyboardEventDisambiguationQuirks(bool);
- bool needsKeyboardEventDisambiguationQuirks() const { return m_needsKeyboardEventDisambiguationQuirks; }
-
- void setDOMPasteAllowed(bool);
- bool isDOMPasteAllowed() const { return m_isDOMPasteAllowed; }
-
- void setUsesPageCache(bool);
- bool usesPageCache() const { return m_usesPageCache; }
-
- void setShrinksStandaloneImagesToFit(bool);
- bool shrinksStandaloneImagesToFit() const { return m_shrinksStandaloneImagesToFit; }
-
- void setShowsURLsInToolTips(bool);
- bool showsURLsInToolTips() const { return m_showsURLsInToolTips; }
-
- void setFTPDirectoryTemplatePath(const String&);
- const String& ftpDirectoryTemplatePath() const { return m_ftpDirectoryTemplatePath; }
-
- void setForceFTPDirectoryListings(bool);
- bool forceFTPDirectoryListings() const { return m_forceFTPDirectoryListings; }
-
- void setDeveloperExtrasEnabled(bool);
- bool developerExtrasEnabled() const { return m_developerExtrasEnabled; }
-
- void setUsesUniversalDetector(bool);
- bool usesEncodingDetector() const { return m_usesEncodingDetector; }
-
- void setAuthorAndUserStylesEnabled(bool);
- bool authorAndUserStylesEnabled() const { return m_authorAndUserStylesEnabled; }
-
- void setFontRenderingMode(FontRenderingMode mode);
- FontRenderingMode fontRenderingMode() const;
-
- void setNeedsSiteSpecificQuirks(bool);
- bool needsSiteSpecificQuirks() const { return m_needsSiteSpecificQuirks; }
-
- void setWebArchiveDebugModeEnabled(bool);
- bool webArchiveDebugModeEnabled() const { return m_webArchiveDebugModeEnabled; }
-
- void setLocalStorageDatabasePath(const String&);
- const String& localStorageDatabasePath() const { return m_localStorageDatabasePath; }
-
- void disableRangeMutationForOldAppleMail(bool);
- bool rangeMutationDisabledForOldAppleMail() const { return m_rangeMutationDisabledForOldAppleMail; }
-
- void setApplicationChromeMode(bool);
- bool inApplicationChromeMode() const { return m_inApplicationChromeMode; }
-
- void setOfflineWebApplicationCacheEnabled(bool);
- bool offlineWebApplicationCacheEnabled() const { return m_offlineWebApplicationCacheEnabled; }
-
- void setShouldPaintCustomScrollbars(bool);
- bool shouldPaintCustomScrollbars() const { return m_shouldPaintCustomScrollbars; }
-
- void setZoomsTextOnly(bool);
- bool zoomsTextOnly() const { return m_zoomsTextOnly; }
-
- void setEnforceCSSMIMETypeInStrictMode(bool);
- bool enforceCSSMIMETypeInStrictMode() { return m_enforceCSSMIMETypeInStrictMode; }
-
- void setAllowScriptsToCloseWindows(bool);
- bool allowScriptsToCloseWindows() const { return m_allow_scripts_to_close_windows; }
-
- private:
- Page* m_page;
-
- String m_defaultTextEncodingName;
- String m_ftpDirectoryTemplatePath;
- String m_localStorageDatabasePath;
- KURL m_userStyleSheetLocation;
- AtomicString m_standardFontFamily;
- AtomicString m_fixedFontFamily;
- AtomicString m_serifFontFamily;
- AtomicString m_sansSerifFontFamily;
- AtomicString m_cursiveFontFamily;
- AtomicString m_fantasyFontFamily;
- EditableLinkBehavior m_editableLinkBehavior;
- int m_minimumFontSize;
- int m_minimumLogicalFontSize;
- int m_defaultFontSize;
- int m_defaultFixedFontSize;
- bool m_isJavaEnabled : 1;
- bool m_loadsImagesAutomatically : 1;
- bool m_privateBrowsingEnabled : 1;
- bool m_arePluginsEnabled : 1;
- bool m_isJavaScriptEnabled : 1;
- bool m_javaScriptCanOpenWindowsAutomatically : 1;
- bool m_shouldPrintBackgrounds : 1;
- bool m_textAreasAreResizable : 1;
-#if ENABLE(DASHBOARD_SUPPORT)
- bool m_usesDashboardBackwardCompatibilityMode : 1;
-#endif
- bool m_needsAdobeFrameReloadingQuirk : 1;
- bool m_needsKeyboardEventDisambiguationQuirks : 1;
- bool m_isDOMPasteAllowed : 1;
- bool m_shrinksStandaloneImagesToFit : 1;
- bool m_usesPageCache: 1;
- bool m_showsURLsInToolTips : 1;
- bool m_forceFTPDirectoryListings : 1;
- bool m_developerExtrasEnabled : 1;
- bool m_authorAndUserStylesEnabled : 1;
- bool m_needsSiteSpecificQuirks : 1;
- unsigned m_fontRenderingMode : 1;
- bool m_webArchiveDebugModeEnabled : 1;
- bool m_inApplicationChromeMode : 1;
- bool m_offlineWebApplicationCacheEnabled : 1;
- bool m_rangeMutationDisabledForOldAppleMail : 1;
- bool m_shouldPaintCustomScrollbars : 1;
- bool m_zoomsTextOnly : 1;
- bool m_enforceCSSMIMETypeInStrictMode : 1;
- bool m_usesEncodingDetector : 1;
- bool m_allow_scripts_to_close_windows : 1;
- };
-
-} // namespace WebCore
-
-#endif // Settings_h
diff --git a/webkit/pending/SimpleFontData.cpp b/webkit/pending/SimpleFontData.cpp
deleted file mode 100644
index 14578a8..0000000
--- a/webkit/pending/SimpleFontData.cpp
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2005, 2008 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2006 Alexey Proskuryakov
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "SimpleFontData.h"
-
-#include "FontCache.h"
-
-#if ENABLE(SVG_FONTS)
-#include "SVGFontData.h"
-#include "SVGFontFaceElement.h"
-#endif
-
-#include <wtf/MathExtras.h>
-
-namespace WebCore {
-
-SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData)
- : m_font(f)
- , m_treatAsFixedPitch(false)
-#if ENABLE(SVG_FONTS)
- , m_svgFontData(svgFontData)
-#endif
- , m_isCustomFont(customFont)
- , m_isLoading(loading)
- , m_smallCapsFontData(0)
- , m_zeroWidthFontData(new ZeroWidthFontData())
- , m_cjkWidthFontData(new CJKWidthFontData())
-{
-#if ENABLE(SVG_FONTS) && !PLATFORM(QT)
- if (SVGFontFaceElement* svgFontFaceElement = svgFontData ? svgFontData->svgFontFaceElement() : 0) {
- m_unitsPerEm = svgFontFaceElement->unitsPerEm();
-
- double scale = f.size();
- if (m_unitsPerEm)
- scale /= m_unitsPerEm;
-
- m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale);
- m_descent = static_cast<int>(svgFontFaceElement->descent() * scale);
- // TODO(ojan): What should SVG fonts use for avgCharWidth/maxCharWidth?
- // This is currently only used in RenderTextControl.cpp for the width
- // of textareas with a non-fixed width.
- m_avgCharWidth = 0;
- m_maxCharWidth = 0;
- m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale);
- m_lineGap = 0.1f * f.size();
- m_lineSpacing = m_ascent + m_descent + m_lineGap;
-
- m_spaceGlyph = 0;
- m_spaceWidth = 0;
- m_adjustedSpaceWidth = 0;
- determinePitch();
- m_missingGlyphData.fontData = this;
- m_missingGlyphData.glyph = 0;
- m_zeroWidthFontData->init(this);
- m_cjkWidthFontData->init(this);
- return;
- }
-#endif
-
- platformInit();
-
- GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
- if (!glyphPageZero) {
- LOG_ERROR("Failed to get glyph page zero.");
- m_spaceGlyph = 0;
- m_spaceWidth = 0;
- m_adjustedSpaceWidth = 0;
- determinePitch();
- m_missingGlyphData.fontData = this;
- m_missingGlyphData.glyph = 0;
- m_zeroWidthFontData->init(this);
- m_cjkWidthFontData->init(this);
- return;
- }
-
- // Nasty hack to determine if we should round or ceil space widths.
- // If the font is monospace or fake monospace we ceil to ensure that
- // every character and the space are the same width. Otherwise we round.
- static const UChar32 space_char = ' ';
- m_spaceGlyph = glyphPageZero->glyphDataForCharacter(space_char).glyph;
- float width = widthForGlyph(m_spaceGlyph);
- m_spaceWidth = width;
- determinePitch();
- m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width);
-
- // TODO(dglazkov): Investigate and implement across platforms, if needed
-#if PLATFORM(WIN)
- // ZERO WIDTH SPACES are explicitly mapped to share the glyph
- // with SPACE (with width adjusted to 0) during GlyphPage::fill
- // This is currently only implemented for Windows port. The FontData
- // remapping may very well be needed for other platforms.
-#else
- // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is shared with SPACE.
- // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph.
- // See <http://bugs.webkit.org/show_bug.cgi?id=13178>
- // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0,
- // are mapped to the ZERO WIDTH SPACE glyph.
- Glyph zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph;
- if (zeroWidthSpaceGlyph) {
- if (zeroWidthSpaceGlyph != m_spaceGlyph)
- m_glyphToWidthMap.setWidthForGlyph(zeroWidthSpaceGlyph, 0);
- else
- LOG_ERROR("Font maps SPACE and ZERO WIDTH SPACE to the same glyph. Glyph width not overridden.");
- }
-#endif
-
- m_missingGlyphData.fontData = this;
- m_missingGlyphData.glyph = 0;
- m_zeroWidthFontData->init(this);
- m_cjkWidthFontData->init(this);
-}
-
-SimpleFontData::SimpleFontData()
- : m_treatAsFixedPitch(false)
-#if ENABLE(SVG_FONTS)
- , m_svgFontData(0)
-#endif
- , m_isCustomFont(0)
- , m_isLoading(0)
- , m_smallCapsFontData(0)
-{
-}
-
-SimpleFontData::~SimpleFontData()
-{
- if (!isCustomFont()) {
- if (m_smallCapsFontData)
- FontCache::releaseFontData(m_smallCapsFontData);
- GlyphPageTreeNode::pruneTreeFontData(this);
- }
-
-#if ENABLE(SVG_FONTS) && !PLATFORM(QT)
- if (!m_svgFontData || !m_svgFontData->svgFontFaceElement())
-#endif
- platformDestroy();
-}
-
-float SimpleFontData::widthForGlyph(Glyph glyph) const
-{
- float width = m_glyphToWidthMap.widthForGlyph(glyph);
- if (width != cGlyphWidthUnknown)
- return width;
-
- width = platformWidthForGlyph(glyph);
- m_glyphToWidthMap.setWidthForGlyph(glyph, width);
-
- return width;
-}
-
-const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const
-{
- return this;
-}
-
-bool SimpleFontData::isSegmented() const
-{
- return false;
-}
-
-const SimpleFontData* SimpleFontData::zeroWidthFontData() const
-{
- return m_zeroWidthFontData.get();
-}
-
-const SimpleFontData* SimpleFontData::cjkWidthFontData() const
-{
- return m_cjkWidthFontData.get();
-}
-
-void ZeroWidthFontData::init(SimpleFontData* fontData)
-{
- m_font = fontData->m_font;
- m_smallCapsFontData = fontData->m_smallCapsFontData;
- m_ascent = fontData->m_ascent;
- m_descent = fontData->m_descent;
- m_lineSpacing = fontData->m_lineSpacing;
- m_lineGap = fontData->m_lineGap;
- m_maxCharWidth = 0;
- m_avgCharWidth = 0;
- m_xHeight = fontData->m_xHeight;
- m_unitsPerEm = fontData->m_unitsPerEm;
- m_spaceWidth = 0;
- m_spaceGlyph = 0;
- m_adjustedSpaceWidth = fontData->m_adjustedSpaceWidth;
-#if PLATFORM(WIN)
- m_scriptCache = 0;
- m_scriptFontProperties = 0;
-#endif
-}
-
-CJKWidthFontData::CJKWidthFontData()
- : m_cjkGlyphWidth(cGlyphWidthUnknown)
-{
-}
-
-float CJKWidthFontData::widthForGlyph(Glyph glyph) const
-{
- if (m_cjkGlyphWidth != cGlyphWidthUnknown)
- return m_cjkGlyphWidth;
-
- float width = platformWidthForGlyph(glyph);
- m_cjkGlyphWidth = width;
-
-#ifndef NDEBUG
- // Test our optimization that assuming all CGK glyphs have the same width
- const float actual_width = platformWidthForGlyph(glyph);
- ASSERT((cGlyphWidthUnknown == width) || (actual_width == width));
-#endif
-
- return width;
-}
-
-// static
-// TODO(dglazkov): Move to Font::isCJKCodePoint for consistency
-bool SimpleFontData::isCJKCodePoint(UChar32 c)
-{
- // AC00..D7AF; Hangul Syllables
- if ((0xAC00 <= c) && (c <= 0xD7AF))
- return true;
-
- // CJK ideographs
- UErrorCode errorCode = U_ZERO_ERROR; // has to be initialized.
- return uscript_getScript(c, &errorCode) == USCRIPT_HAN &&
- U_SUCCESS(errorCode);
-}
-
-
-} // namespace WebCore
diff --git a/webkit/pending/SimpleFontData.h b/webkit/pending/SimpleFontData.h
deleted file mode 100644
index 1c066a4..0000000
--- a/webkit/pending/SimpleFontData.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * This file is part of the internal font implementation.
- *
- * Copyright (C) 2006, 2008 Apple Computer, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef SimpleFontData_h
-#define SimpleFontData_h
-
-#include "FontData.h"
-#include "FontPlatformData.h"
-#include "GlyphPageTreeNode.h"
-#include "GlyphWidthMap.h"
-#include <wtf/OwnPtr.h>
-
-#if PLATFORM(MAC)
-typedef struct OpaqueATSUStyle* ATSUStyle;
-#endif
-
-#if PLATFORM(WIN)
-#include <usp10.h>
-#endif
-
-#if PLATFORM(CAIRO)
-#include <cairo.h>
-#endif
-
-namespace WebCore {
-
-class FontDescription;
-class FontPlatformData;
-class SharedBuffer;
-class SVGFontData;
-class WidthMap;
-class ZeroWidthFontData;
-class CJKWidthFontData;
-
-enum Pitch { UnknownPitch, FixedPitch, VariablePitch };
-
-class SimpleFontData : public FontData {
-public:
- SimpleFontData(const FontPlatformData&, bool customFont = false, bool loading = false, SVGFontData* data = 0);
- virtual ~SimpleFontData();
-
-protected:
- // sub-class constructor
- SimpleFontData();
-
-public:
- const FontPlatformData& platformData() const { return m_font; }
- SimpleFontData* smallCapsFontData(const FontDescription& fontDescription) const;
-
- // vertical metrics
- int ascent() const { return m_ascent; }
- int descent() const { return m_descent; }
- int lineSpacing() const { return m_lineSpacing; }
- int lineGap() const { return m_lineGap; }
- int maxCharWidth() const { return m_maxCharWidth; }
- int avgCharWidth() const { return m_avgCharWidth; }
-
- float xHeight() const { return m_xHeight; }
- unsigned unitsPerEm() const { return m_unitsPerEm; }
-
- virtual float widthForGlyph(Glyph) const;
- float platformWidthForGlyph(Glyph) const;
-
- virtual const SimpleFontData* fontDataForCharacter(UChar32) const;
- virtual bool containsCharacters(const UChar*, int length) const;
-
- void determinePitch();
- Pitch pitch() const { return m_treatAsFixedPitch ? FixedPitch : VariablePitch; }
-
- static bool isCJKCodePoint(UChar32 c);
-
-#if ENABLE(SVG_FONTS)
- SVGFontData* svgFontData() const { return m_svgFontData.get(); }
- bool isSVGFont() const { return m_svgFontData; }
-#else
- bool isSVGFont() const { return false; }
-#endif
-
- virtual bool isCustomFont() const { return m_isCustomFont; }
- virtual bool isLoading() const { return m_isLoading; }
- virtual bool isSegmented() const;
-
- const GlyphData& missingGlyphData() const { return m_missingGlyphData; }
-
-#if PLATFORM(MAC)
- NSFont* getNSFont() const { return m_font.font(); }
- void checkShapesArabic() const;
- bool shapesArabic() const
- {
- if (!m_checkedShapesArabic)
- checkShapesArabic();
- return m_shapesArabic;
- }
-#endif
-
-#if PLATFORM(WIN)
- bool isSystemFont() const { return m_isSystemFont; }
- SCRIPT_FONTPROPERTIES* scriptFontProperties() const;
- SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; }
-
- static void setShouldApplyMacAscentHack(bool);
- static bool shouldApplyMacAscentHack();
-#endif
-
-#if PLATFORM(GTK) && PLATFORM(CAIRO)
- void setFont(cairo_t*) const;
-#endif
-
-#if PLATFORM(WX)
- wxFont getWxFont() const { return m_font.font(); }
-#endif
-
- const SimpleFontData* zeroWidthFontData() const;
- const SimpleFontData* cjkWidthFontData() const;
-
-private:
- void platformInit();
- void platformDestroy();
-
- void commonInit();
-
-#if PLATFORM(WIN)
- void initGDIFont();
- void platformCommonDestroy();
- float widthForGDIGlyph(Glyph glyph) const;
-#endif
-
-public:
- int m_ascent;
- int m_descent;
- int m_lineSpacing;
- int m_lineGap;
- int m_maxCharWidth;
- int m_avgCharWidth;
- float m_xHeight;
- unsigned m_unitsPerEm;
-
- FontPlatformData m_font;
-
- mutable GlyphWidthMap m_glyphToWidthMap;
-
- bool m_treatAsFixedPitch;
-
-#if ENABLE(SVG_FONTS)
- OwnPtr<SVGFontData> m_svgFontData;
-#endif
-
- bool m_isCustomFont; // Whether or not we are custom font loaded via @font-face
- bool m_isLoading; // Whether or not this custom font is still in the act of loading.
-
- Glyph m_spaceGlyph;
- float m_spaceWidth;
- float m_adjustedSpaceWidth;
-
- GlyphData m_missingGlyphData;
-
- mutable SimpleFontData* m_smallCapsFontData;
-
-#if PLATFORM(CG) || PLATFORM(WIN)
- float m_syntheticBoldOffset;
-#endif
-
-#if PLATFORM(MAC)
- void* m_styleGroup;
- mutable ATSUStyle m_ATSUStyle;
- mutable bool m_ATSUStyleInitialized;
- mutable bool m_ATSUMirrors;
- mutable bool m_checkedShapesArabic;
- mutable bool m_shapesArabic;
-#endif
-
-#if PLATFORM(WIN)
- bool m_isSystemFont;
- mutable SCRIPT_CACHE m_scriptCache;
- mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties;
-#endif
-
-private:
- OwnPtr<ZeroWidthFontData> m_zeroWidthFontData;
- OwnPtr<CJKWidthFontData> m_cjkWidthFontData;
-};
-
-// SimpleFontData sub-classes:
-
-// Has a single zero-width glyph, used for ZWS and
-// UCHAR_DEFAULT_IGNORABLE_CODE_POINT characters
-class ZeroWidthFontData : public SimpleFontData {
-public:
- void init(SimpleFontData*);
- virtual float widthForGlyph(Glyph) const { return 0.0f; }
-};
-
-// Monospaced, single glyph and width, used for CJK characters
-// The assumption made here can break for some high-quality CJK fonts with
-// proportional CJK glyphs.
-class CJKWidthFontData : public ZeroWidthFontData {
-public:
- CJKWidthFontData();
-
- virtual float widthForGlyph(Glyph) const;
-
-private:
- // Optimization for CJK glyphs
- mutable float m_cjkGlyphWidth;
-};
-
-} // namespace WebCore
-
-#endif // SimpleFontData_h
diff --git a/webkit/pending/TextCodecICU.cpp b/webkit/pending/TextCodecICU.cpp
deleted file mode 100644
index 3dfadea..0000000
--- a/webkit/pending/TextCodecICU.cpp
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2006 Alexey Proskuryakov <ap@nypop.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "TextCodecICU.h"
-
-#include "CharacterNames.h"
-#include "CString.h"
-#include "PlatformString.h"
-#include <unicode/ucnv.h>
-#include <unicode/ucnv_cb.h>
-#include <wtf/Assertions.h>
-
-using std::auto_ptr;
-using std::min;
-
-namespace WebCore {
-
-const size_t ConversionBufferSize = 16384;
-
-static UConverter* cachedConverterICU;
-
-static auto_ptr<TextCodec> newTextCodecICU(const TextEncoding& encoding, const void*)
-{
- return auto_ptr<TextCodec>(new TextCodecICU(encoding));
-}
-
-void TextCodecICU::registerBaseEncodingNames(EncodingNameRegistrar registrar)
-{
- registrar("UTF-8", "UTF-8");
-}
-
-void TextCodecICU::registerBaseCodecs(TextCodecRegistrar registrar)
-{
- registrar("UTF-8", newTextCodecICU, 0);
-}
-
-// FIXME: Registering all the encodings we get from ucnv_getAvailableName
-// includes encodings we don't want or need. For example: UTF16_PlatformEndian,
-// UTF16_OppositeEndian, UTF32_PlatformEndian, UTF32_OppositeEndian, and all
-// the encodings with commas and version numbers.
-
-void TextCodecICU::registerExtendedEncodingNames(EncodingNameRegistrar registrar)
-{
- // We register Hebrew with logical ordering using a separate name.
- // Otherwise, this would share the same canonical name as the
- // visual ordering case, and then TextEncoding could not tell them
- // apart; ICU works with either name.
- registrar("ISO-8859-8-I", "ISO-8859-8-I");
-
- int32_t numEncodings = ucnv_countAvailable();
- for (int32_t i = 0; i < numEncodings; ++i) {
- const char* name = ucnv_getAvailableName(i);
- UErrorCode error = U_ZERO_ERROR;
- // Try MIME before trying IANA to pick up commonly used names like
- // 'EUC-JP' instead of horrendeously long names like
- // 'Extended_UNIX_Code_Packed_Format_for_Japanese'.
- const char* standardName = ucnv_getStandardName(name, "MIME", &error);
- if (!U_SUCCESS(error) || !standardName) {
- error = U_ZERO_ERROR;
- // Try IANA to pick up 'windows-12xx' and other names
- // which are not preferred MIME names but are widely used.
- standardName = ucnv_getStandardName(name, "IANA", &error);
- if (!U_SUCCESS(error) || !standardName)
- continue;
- }
-
- // Here, we used to alias GB2312 and GB2312-80 to GBK, but our copy
- // of ICU treats GB2312/GB2312-80 as synonyms of GBK so that we
- // don't need that any more.
- // Similarly, EUC-KR encodings all map to an extended version.
- else if (strcmp(standardName, "KS_C_5601-1987") == 0 || strcmp(standardName, "EUC-KR") == 0)
- standardName = "windows-949-2000";
- // And so on.
- else if (strcmp(standardName, "ISO_8859-9:1989") == 0)
- standardName = "windows-1254";
- else if (strcmp(standardName, "TIS-620") == 0)
- standardName = "windows-874-2000";
-
- registrar(standardName, standardName);
-
- uint16_t numAliases = ucnv_countAliases(name, &error);
- ASSERT(U_SUCCESS(error));
- if (U_SUCCESS(error))
- for (uint16_t j = 0; j < numAliases; ++j) {
- error = U_ZERO_ERROR;
- const char* alias = ucnv_getAlias(name, j, &error);
- ASSERT(U_SUCCESS(error));
- if (U_SUCCESS(error) && alias != standardName)
- registrar(alias, standardName);
- }
- }
-
- // We used to map macroman and xmacroman to macintosh, but
- // we don't need them any more because they're added to our
- // local copy of ICU.
-
- // Additional aliases that historically were present in the encoding
- // table in WebKit on Macintosh that don't seem to be present in ICU.
- // Perhaps we can prove these are not used on the web and remove them.
- // Or perhaps we can get them added to ICU.
- registrar("cnbig5", "Big5");
- registrar("cngb", "EUC-CN");
- registrar("csISO88598I", "ISO_8859-8-I");
- registrar("csgb231280", "EUC-CN");
- registrar("dos720", "cp864");
- registrar("dos874", "TIS-620");
- registrar("jis7", "ISO-2022-JP");
- registrar("koi", "KOI8-R");
- registrar("logical", "ISO-8859-8-I");
- registrar("unicode11utf8", "UTF-8");
- registrar("unicode20utf8", "UTF-8");
- registrar("visual", "ISO-8859-8");
- registrar("winarabic", "windows-1256");
- registrar("winbaltic", "windows-1257");
- registrar("wincyrillic", "windows-1251");
- registrar("windows874", "windows874-2000");
- registrar("iso885911", "windows874-2000");
- registrar("wingreek", "windows-1253");
- registrar("winhebrew", "windows-1255");
- registrar("winlatin2", "windows-1250");
- registrar("winturkish", "windows-1254");
- registrar("winvietnamese", "windows-1258");
- registrar("xcp1250", "windows-1250");
- registrar("xcp1251", "windows-1251");
- registrar("xeuc", "EUC-JP");
- registrar("xeuccn", "EUC-CN");
- registrar("xgbk", "EUC-CN");
- registrar("xunicode20utf8", "UTF-8");
- registrar("xwindows949", "windows-949-2000");
- registrar("xxbig5", "Big5");
-}
-
-void TextCodecICU::registerExtendedCodecs(TextCodecRegistrar registrar)
-{
- // See comment above in registerEncodingNames.
- registrar("ISO-8859-8-I", newTextCodecICU, 0);
-
- int32_t numEncodings = ucnv_countAvailable();
- for (int32_t i = 0; i < numEncodings; ++i) {
- const char* name = ucnv_getAvailableName(i);
- UErrorCode error = U_ZERO_ERROR;
- // Try MIME before trying IANA to pick up commonly used names like
- // 'EUC-JP' instead of horrendeously long names like
- // 'Extended_UNIX_Code_Packed_Format_for_Japanese'.
- const char* standardName = ucnv_getStandardName(name, "MIME", &error);
- if (!U_SUCCESS(error) || !standardName) {
- error = U_ZERO_ERROR;
- // Try IANA to pick up 'windows-12xx' and other names
- // which are not preferred MIME names but are widely used.
- standardName = ucnv_getStandardName(name, "IANA", &error);
- if (!U_SUCCESS(error) || !standardName)
- continue;
- }
- registrar(standardName, newTextCodecICU, 0);
- }
-}
-
-TextCodecICU::TextCodecICU(const TextEncoding& encoding)
- : m_encoding(encoding)
- , m_numBufferedBytes(0)
- , m_converterICU(0)
- , m_needsGBKFallbacks(false)
-{
-}
-
-TextCodecICU::~TextCodecICU()
-{
- releaseICUConverter();
-}
-
-void TextCodecICU::releaseICUConverter() const
-{
- if (m_converterICU) {
- if (cachedConverterICU)
- ucnv_close(cachedConverterICU);
- cachedConverterICU = m_converterICU;
- m_converterICU = 0;
- }
-}
-
-void TextCodecICU::createICUConverter() const
-{
- ASSERT(!m_converterICU);
-
- const char* name = m_encoding.name();
- m_needsGBKFallbacks = name[0] == 'G' && name[1] == 'B' && name[2] == 'K' && !name[3];
-
- UErrorCode err;
-
- if (cachedConverterICU) {
- err = U_ZERO_ERROR;
- const char* cachedName = ucnv_getName(cachedConverterICU, &err);
- if (U_SUCCESS(err) && m_encoding == cachedName) {
- m_converterICU = cachedConverterICU;
- cachedConverterICU = 0;
- return;
- }
- }
-
- err = U_ZERO_ERROR;
- m_converterICU = ucnv_open(m_encoding.name(), &err);
-#if !LOG_DISABLED
- if (err == U_AMBIGUOUS_ALIAS_WARNING)
- LOG_ERROR("ICU ambiguous alias warning for encoding: %s", m_encoding.name());
-#endif
- if (m_converterICU)
- ucnv_setFallback(m_converterICU, TRUE);
-}
-
-int TextCodecICU::decodeToBuffer(UChar* target, UChar* targetLimit, const char*& source, const char* sourceLimit, int32_t* offsets, bool flush, UErrorCode& err)
-{
- UChar* targetStart = target;
- err = U_ZERO_ERROR;
- ucnv_toUnicode(m_converterICU, &target, targetLimit, &source, sourceLimit, offsets, flush, &err);
- return target - targetStart;
-}
-
-class ErrorCallbackSetter {
-public:
- ErrorCallbackSetter(UConverter* converter, bool stopOnError)
- : m_converter(converter)
- , m_shouldStopOnEncodingErrors(stopOnError)
- {
- if (m_shouldStopOnEncodingErrors) {
- UErrorCode err = U_ZERO_ERROR;
- ucnv_setToUCallBack(m_converter, UCNV_TO_U_CALLBACK_SUBSTITUTE,
- UCNV_SUB_STOP_ON_ILLEGAL, &m_savedAction,
- &m_savedContext, &err);
- ASSERT(err == U_ZERO_ERROR);
- }
- }
- ~ErrorCallbackSetter()
- {
- if (m_shouldStopOnEncodingErrors) {
- UErrorCode err = U_ZERO_ERROR;
- const void* oldContext;
- UConverterToUCallback oldAction;
- ucnv_setToUCallBack(m_converter, m_savedAction,
- m_savedContext, &oldAction,
- &oldContext, &err);
- ASSERT(oldAction == UCNV_TO_U_CALLBACK_SUBSTITUTE);
- ASSERT(!strcmp(static_cast<const char*>(oldContext), UCNV_SUB_STOP_ON_ILLEGAL));
- ASSERT(err == U_ZERO_ERROR);
- }
- }
-private:
- UConverter* m_converter;
- bool m_shouldStopOnEncodingErrors;
- const void* m_savedContext;
- UConverterToUCallback m_savedAction;
-};
-
-String TextCodecICU::decode(const char* bytes, size_t length, bool flush, bool stopOnError, bool& sawError)
-{
- // Get a converter for the passed-in encoding.
- if (!m_converterICU) {
- createICUConverter();
- ASSERT(m_converterICU);
- if (!m_converterICU) {
- LOG_ERROR("error creating ICU encoder even though encoding was in table");
- return String();
- }
- }
-
- ErrorCallbackSetter callbackSetter(m_converterICU, stopOnError);
-
- Vector<UChar> result;
-
- UChar buffer[ConversionBufferSize];
- UChar* bufferLimit = buffer + ConversionBufferSize;
- const char* source = reinterpret_cast<const char*>(bytes);
- const char* sourceLimit = source + length;
- int32_t* offsets = NULL;
- UErrorCode err = U_ZERO_ERROR;
-
- do {
- int ucharsDecoded = decodeToBuffer(buffer, bufferLimit, source, sourceLimit, offsets, flush, err);
- result.append(buffer, ucharsDecoded);
- } while (err == U_BUFFER_OVERFLOW_ERROR);
-
- if (U_FAILURE(err)) {
- // flush the converter so it can be reused, and not be bothered by this error.
- do {
- decodeToBuffer(buffer, bufferLimit, source, sourceLimit, offsets, true, err);
- } while (source < sourceLimit);
- sawError = true;
- }
-
- String resultString = String::adopt(result);
-
- // <http://bugs.webkit.org/show_bug.cgi?id=17014>
- // Simplified Chinese pages use the code A3A0 to mean "full-width space", but ICU decodes it as U+E5E5.
- if (m_encoding == "GBK" || m_encoding == "gb18030")
- resultString.replace(0xE5E5, ideographicSpace);
-
- return resultString;
-}
-
-// We need to apply these fallbacks ourselves as they are not currently supported by ICU and
-// they were provided by the old TEC encoding path
-// Needed to fix <rdar://problem/4708689>
-static UChar getGbkEscape(UChar32 codePoint)
-{
- switch (codePoint) {
- case 0x01F9:
- return 0xE7C8;
- case 0x1E3F:
- return 0xE7C7;
- case 0x22EF:
- return 0x2026;
- case 0x301C:
- return 0xFF5E;
- default:
- return 0;
- }
-}
-
-// Invalid character handler when writing escaped entities for unrepresentable
-// characters. See the declaration of TextCodec::encode for more.
-static void urlEscapedEntityCallback(const void* context, UConverterFromUnicodeArgs* fromUArgs, const UChar* codeUnits, int32_t length,
- UChar32 codePoint, UConverterCallbackReason reason, UErrorCode* err)
-{
- if (reason == UCNV_UNASSIGNED) {
- *err = U_ZERO_ERROR;
-
- UnencodableReplacementArray entity;
- int entityLen = TextCodec::getUnencodableReplacement(codePoint, URLEncodedEntitiesForUnencodables, entity);
- ucnv_cbFromUWriteBytes(fromUArgs, entity, entityLen, 0, err);
- } else
- UCNV_FROM_U_CALLBACK_ESCAPE(context, fromUArgs, codeUnits, length, codePoint, reason, err);
-}
-
-// Substitutes special GBK characters, escaping all other unassigned entities.
-static void gbkCallbackEscape(const void* context, UConverterFromUnicodeArgs* fromUArgs, const UChar* codeUnits, int32_t length,
- UChar32 codePoint, UConverterCallbackReason reason, UErrorCode* err)
-{
- UChar outChar;
- if (reason == UCNV_UNASSIGNED && (outChar = getGbkEscape(codePoint))) {
- const UChar* source = &outChar;
- *err = U_ZERO_ERROR;
- ucnv_cbFromUWriteUChars(fromUArgs, &source, source + 1, 0, err);
- return;
- }
- UCNV_FROM_U_CALLBACK_ESCAPE(context, fromUArgs, codeUnits, length, codePoint, reason, err);
-}
-
-// Combines both gbkUrlEscapedEntityCallback and GBK character substitution.
-static void gbkUrlEscapedEntityCallack(const void* context, UConverterFromUnicodeArgs* fromUArgs, const UChar* codeUnits, int32_t length,
- UChar32 codePoint, UConverterCallbackReason reason, UErrorCode* err)
-{
- if (reason == UCNV_UNASSIGNED) {
- if (UChar outChar = getGbkEscape(codePoint)) {
- const UChar* source = &outChar;
- *err = U_ZERO_ERROR;
- ucnv_cbFromUWriteUChars(fromUArgs, &source, source + 1, 0, err);
- return;
- }
- urlEscapedEntityCallback(context, fromUArgs, codeUnits, length, codePoint, reason, err);
- return;
- }
- UCNV_FROM_U_CALLBACK_ESCAPE(context, fromUArgs, codeUnits, length, codePoint, reason, err);
-}
-
-static void gbkCallbackSubstitute(const void* context, UConverterFromUnicodeArgs* fromUArgs, const UChar* codeUnits, int32_t length,
- UChar32 codePoint, UConverterCallbackReason reason, UErrorCode* err)
-{
- UChar outChar;
- if (reason == UCNV_UNASSIGNED && (outChar = getGbkEscape(codePoint))) {
- const UChar* source = &outChar;
- *err = U_ZERO_ERROR;
- ucnv_cbFromUWriteUChars(fromUArgs, &source, source + 1, 0, err);
- return;
- }
- UCNV_FROM_U_CALLBACK_SUBSTITUTE(context, fromUArgs, codeUnits, length, codePoint, reason, err);
-}
-
-CString TextCodecICU::encode(const UChar* characters, size_t length, UnencodableHandling handling)
-{
- if (!length)
- return "";
-
- if (!m_converterICU)
- createICUConverter();
- if (!m_converterICU)
- return CString();
-
- // FIXME: We should see if there is "force ASCII range" mode in ICU;
- // until then, we change the backslash into a yen sign.
- // Encoding will change the yen sign back into a backslash.
- String copy(characters, length);
- copy.replace('\\', m_encoding.backslashAsCurrencySymbol());
-
- const UChar* source = copy.characters();
- const UChar* sourceLimit = source + copy.length();
-
- UErrorCode err = U_ZERO_ERROR;
-
- switch (handling) {
- case QuestionMarksForUnencodables:
- ucnv_setSubstChars(m_converterICU, "?", 1, &err);
- ucnv_setFromUCallBack(m_converterICU, m_needsGBKFallbacks ? gbkCallbackSubstitute : UCNV_FROM_U_CALLBACK_SUBSTITUTE, 0, 0, 0, &err);
- break;
- case EntitiesForUnencodables:
- ucnv_setFromUCallBack(m_converterICU, m_needsGBKFallbacks ? gbkCallbackEscape : UCNV_FROM_U_CALLBACK_ESCAPE, UCNV_ESCAPE_XML_DEC, 0, 0, &err);
- break;
- case URLEncodedEntitiesForUnencodables:
- ucnv_setFromUCallBack(m_converterICU, m_needsGBKFallbacks ? gbkUrlEscapedEntityCallack : urlEscapedEntityCallback, 0, 0, 0, &err);
- break;
- }
-
- ASSERT(U_SUCCESS(err));
- if (U_FAILURE(err))
- return CString();
-
- Vector<char> result;
- size_t size = 0;
- do {
- char buffer[ConversionBufferSize];
- char* target = buffer;
- char* targetLimit = target + ConversionBufferSize;
- err = U_ZERO_ERROR;
- ucnv_fromUnicode(m_converterICU, &target, targetLimit, &source, sourceLimit, 0, true, &err);
- size_t count = target - buffer;
- result.grow(size + count);
- memcpy(result.data() + size, buffer, count);
- size += count;
- } while (err == U_BUFFER_OVERFLOW_ERROR);
-
- return CString(result.data(), size);
-}
-
-
-} // namespace WebCore
diff --git a/webkit/pending/TextResourceDecoder.cpp b/webkit/pending/TextResourceDecoder.cpp
deleted file mode 100644
index fc4e10e1..0000000
--- a/webkit/pending/TextResourceDecoder.cpp
+++ /dev/null
@@ -1,894 +0,0 @@
-/*
- Copyright (C) 1999 Lars Knoll (knoll@mpi-hd.mpg.de)
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- Copyright (C) 2005, 2006, 2007 Alexey Proskuryakov (ap@nypop.com)
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-
-#include "config.h"
-#include "TextResourceDecoder.h"
-
-#include "DOMImplementation.h"
-#include "HTMLNames.h"
-#include "TextCodec.h"
-#include <wtf/ASCIICType.h>
-
-#include "unicode/ucnv.h"
-#include "unicode/ucsdet.h"
-
-using namespace WTF;
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-// You might think we should put these find functions elsewhere, perhaps with the
-// similar functions that operate on UChar, but arguably only the decoder has
-// a reason to process strings of char rather than UChar.
-
-static int find(const char* subject, size_t subjectLength, const char* target)
-{
- size_t targetLength = strlen(target);
- if (targetLength > subjectLength)
- return -1;
- for (size_t i = 0; i <= subjectLength - targetLength; ++i) {
- bool match = true;
- for (size_t j = 0; j < targetLength; ++j) {
- if (subject[i + j] != target[j]) {
- match = false;
- break;
- }
- }
- if (match)
- return i;
- }
- return -1;
-}
-
-static int findIgnoringCase(const char* subject, size_t subjectLength, const char* target)
-{
- size_t targetLength = strlen(target);
- if (targetLength > subjectLength)
- return -1;
-#ifndef NDEBUG
- for (size_t i = 0; i < targetLength; ++i)
- ASSERT(isASCIILower(target[i]));
-#endif
- for (size_t i = 0; i <= subjectLength - targetLength; ++i) {
- bool match = true;
- for (size_t j = 0; j < targetLength; ++j) {
- if (toASCIILower(subject[i + j]) != target[j]) {
- match = false;
- break;
- }
- }
- if (match)
- return i;
- }
- return -1;
-}
-
-static TextEncoding findTextEncoding(const char* encodingName, int length)
-{
- Vector<char, 64> buffer(length + 1);
- memcpy(buffer.data(), encodingName, length);
- buffer[length] = '\0';
- return buffer.data();
-}
-
-class KanjiCode {
-public:
- enum Type { ASCII, JIS, EUC, SJIS, UTF16, UTF8 };
- static enum Type judge(const char* str, int length);
- static const int ESC = 0x1b;
- static const unsigned char sjisMap[256];
- static int ISkanji(int code)
- {
- if (code >= 0x100)
- return 0;
- return sjisMap[code & 0xff] & 1;
- }
- static int ISkana(int code)
- {
- if (code >= 0x100)
- return 0;
- return sjisMap[code & 0xff] & 2;
- }
-};
-
-const unsigned char KanjiCode::sjisMap[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0
-};
-
-/*
- * EUC-JP is
- * [0xa1 - 0xfe][0xa1 - 0xfe]
- * 0x8e[0xa1 - 0xfe](SS2)
- * 0x8f[0xa1 - 0xfe][0xa1 - 0xfe](SS3)
- *
- * Shift_Jis is
- * [0x81 - 0x9f, 0xe0 - 0xef(0xfe?)][0x40 - 0x7e, 0x80 - 0xfc]
- *
- * Shift_Jis Hankaku Kana is
- * [0xa1 - 0xdf]
- */
-
-/*
- * KanjiCode::judge() is based on judge_jcode() from jvim
- * http://hp.vector.co.jp/authors/VA003457/vim/
- *
- * Special Thanks to Kenichi Tsuchida
- */
-
-enum KanjiCode::Type KanjiCode::judge(const char* str, int size)
-{
- enum Type code;
- int i;
- int bfr = false; /* Kana Moji */
- int bfk = 0; /* EUC Kana */
- int sjis = 0;
- int euc = 0;
-
- const unsigned char* ptr = reinterpret_cast<const unsigned char*>(str);
-
- code = ASCII;
-
- i = 0;
- while (i < size) {
- if (ptr[i] == ESC && (size - i >= 3)) {
- if ((ptr[i + 1] == '$' && ptr[i + 2] == 'B')
- || (ptr[i + 1] == '(' && ptr[i + 2] == 'B')) {
- code = JIS;
- goto breakBreak;
- } else if ((ptr[i + 1] == '$' && ptr[i + 2] == '@')
- || (ptr[i + 1] == '(' && ptr[i + 2] == 'J')) {
- code = JIS;
- goto breakBreak;
- } else if (ptr[i + 1] == '(' && ptr[i + 2] == 'I') {
- code = JIS;
- i += 3;
- } else if (ptr[i + 1] == ')' && ptr[i + 2] == 'I') {
- code = JIS;
- i += 3;
- } else {
- i++;
- }
- bfr = false;
- bfk = 0;
- } else {
- if (ptr[i] < 0x20) {
- bfr = false;
- bfk = 0;
- /* ?? check kudokuten ?? && ?? hiragana ?? */
- if ((i >= 2) && (ptr[i - 2] == 0x81)
- && (0x41 <= ptr[i - 1] && ptr[i - 1] <= 0x49)) {
- code = SJIS;
- sjis += 100; /* kudokuten */
- } else if ((i >= 2) && (ptr[i - 2] == 0xa1)
- && (0xa2 <= ptr[i - 1] && ptr[i - 1] <= 0xaa)) {
- code = EUC;
- euc += 100; /* kudokuten */
- } else if ((i >= 2) && (ptr[i - 2] == 0x82) && (0xa0 <= ptr[i - 1])) {
- sjis += 40; /* hiragana */
- } else if ((i >= 2) && (ptr[i - 2] == 0xa4) && (0xa0 <= ptr[i - 1])) {
- euc += 40; /* hiragana */
- }
- } else {
- /* ?? check hiragana or katana ?? */
- if ((size - i > 1) && (ptr[i] == 0x82) && (0xa0 <= ptr[i + 1])) {
- sjis++; /* hiragana */
- } else if ((size - i > 1) && (ptr[i] == 0x83)
- && (0x40 <= ptr[i + 1] && ptr[i + 1] <= 0x9f)) {
- sjis++; /* katakana */
- } else if ((size - i > 1) && (ptr[i] == 0xa4) && (0xa0 <= ptr[i + 1])) {
- euc++; /* hiragana */
- } else if ((size - i > 1) && (ptr[i] == 0xa5) && (0xa0 <= ptr[i + 1])) {
- euc++; /* katakana */
- }
- if (bfr) {
- if ((i >= 1) && (0x40 <= ptr[i] && ptr[i] <= 0xa0) && ISkanji(ptr[i - 1])) {
- code = SJIS;
- goto breakBreak;
- } else if ((i >= 1) && (0x81 <= ptr[i - 1] && ptr[i - 1] <= 0x9f) && ((0x40 <= ptr[i] && ptr[i] < 0x7e) || (0x7e < ptr[i] && ptr[i] <= 0xfc))) {
- code = SJIS;
- goto breakBreak;
- } else if ((i >= 1) && (0xfd <= ptr[i] && ptr[i] <= 0xfe) && (0xa1 <= ptr[i - 1] && ptr[i - 1] <= 0xfe)) {
- code = EUC;
- goto breakBreak;
- } else if ((i >= 1) && (0xfd <= ptr[i - 1] && ptr[i - 1] <= 0xfe) && (0xa1 <= ptr[i] && ptr[i] <= 0xfe)) {
- code = EUC;
- goto breakBreak;
- } else if ((i >= 1) && (ptr[i] < 0xa0 || 0xdf < ptr[i]) && (0x8e == ptr[i - 1])) {
- code = SJIS;
- goto breakBreak;
- } else if (ptr[i] <= 0x7f) {
- code = SJIS;
- goto breakBreak;
- } else {
- if (0xa1 <= ptr[i] && ptr[i] <= 0xa6) {
- euc++; /* sjis hankaku kana kigo */
- } else if (0xa1 <= ptr[i] && ptr[i] <= 0xdf) {
- ; /* sjis hankaku kana */
- } else if (0xa1 <= ptr[i] && ptr[i] <= 0xfe) {
- euc++;
- } else if (0x8e == ptr[i]) {
- euc++;
- } else if (0x20 <= ptr[i] && ptr[i] <= 0x7f) {
- sjis++;
- }
- bfr = false;
- bfk = 0;
- }
- } else if (0x8e == ptr[i]) {
- if (size - i <= 1) {
- ;
- } else if (0xa1 <= ptr[i + 1] && ptr[i + 1] <= 0xdf) {
- /* EUC KANA or SJIS KANJI */
- if (bfk == 1) {
- euc += 100;
- }
- bfk++;
- i++;
- } else {
- /* SJIS only */
- code = SJIS;
- goto breakBreak;
- }
- } else if (0x81 <= ptr[i] && ptr[i] <= 0x9f) {
- /* SJIS only */
- code = SJIS;
- if ((size - i >= 1)
- && ((0x40 <= ptr[i + 1] && ptr[i + 1] <= 0x7e)
- || (0x80 <= ptr[i + 1] && ptr[i + 1] <= 0xfc))) {
- goto breakBreak;
- }
- } else if (0xfd <= ptr[i] && ptr[i] <= 0xfe) {
- /* EUC only */
- code = EUC;
- if ((size - i >= 1)
- && (0xa1 <= ptr[i + 1] && ptr[i + 1] <= 0xfe)) {
- goto breakBreak;
- }
- } else if (ptr[i] <= 0x7f) {
- ;
- } else {
- bfr = true;
- bfk = 0;
- }
- }
- i++;
- }
- }
- if (code == ASCII) {
- if (sjis > euc) {
- code = SJIS;
- } else if (sjis < euc) {
- code = EUC;
- }
- }
-breakBreak:
- return (code);
-}
-
-TextResourceDecoder::ContentType TextResourceDecoder::determineContentType(const String& mimeType)
-{
- if (equalIgnoringCase(mimeType, "text/css"))
- return CSS;
- if (equalIgnoringCase(mimeType, "text/html"))
- return HTML;
- if (DOMImplementation::isXMLMIMEType(mimeType))
- return XML;
- return PlainText;
-}
-
-const TextEncoding& TextResourceDecoder::defaultEncoding(ContentType contentType, const TextEncoding& specifiedDefaultEncoding)
-{
- // Despite 8.5 "Text/xml with Omitted Charset" of RFC 3023, we assume UTF-8 instead of US-ASCII
- // for text/xml. This matches Firefox.
- if (contentType == XML)
- return UTF8Encoding();
- if (!specifiedDefaultEncoding.isValid())
- return Latin1Encoding();
- return specifiedDefaultEncoding;
-}
-
-TextResourceDecoder::TextResourceDecoder(const String& mimeType, const TextEncoding& specifiedDefaultEncoding, bool usesEncodingDetector, const TextResourceDecoder* hintDecoder)
- : m_contentType(determineContentType(mimeType))
- , m_decoder(defaultEncoding(m_contentType, specifiedDefaultEncoding))
- , m_hintDecoder(hintDecoder)
- , m_source(DefaultEncoding)
- , m_checkedForBOM(false)
- , m_checkedForCSSCharset(false)
- , m_checkedForHeadCharset(false)
- , m_sawError(false)
- , m_usesEncodingDetector(usesEncodingDetector)
-{
-}
-
-TextResourceDecoder::~TextResourceDecoder()
-{
-}
-
-void TextResourceDecoder::setEncoding(const TextEncoding& encoding, EncodingSource source)
-{
- // In case the encoding didn't exist, we keep the old one (helps some sites specifying invalid encodings).
- if (!encoding.isValid())
- return;
-
- if (source == EncodingFromMetaTag || source == EncodingFromXMLHeader || source == EncodingFromCSSCharset)
- m_decoder.reset(encoding.closest8BitEquivalent());
- else
- m_decoder.reset(encoding);
-
- m_source = source;
-}
-
-// Returns the position of the encoding string.
-static int findXMLEncoding(const char* str, int len, int& encodingLength)
-{
- int pos = find(str, len, "encoding");
- if (pos == -1)
- return -1;
- pos += 8;
-
- // Skip spaces and stray control characters.
- while (pos < len && str[pos] <= ' ')
- ++pos;
-
- // Skip equals sign.
- if (pos >= len || str[pos] != '=')
- return -1;
- ++pos;
-
- // Skip spaces and stray control characters.
- while (pos < len && str[pos] <= ' ')
- ++pos;
-
- // Skip quotation mark.
- if (pos >= len)
- return - 1;
- char quoteMark = str[pos];
- if (quoteMark != '"' && quoteMark != '\'')
- return -1;
- ++pos;
-
- // Find the trailing quotation mark.
- int end = pos;
- while (end < len && str[end] != quoteMark)
- ++end;
-
- if (end >= len)
- return -1;
- encodingLength = end - pos;
- return pos;
-}
-
-// true if there is more to parse
-static inline bool skipWhitespace(const char*& pos, const char* dataEnd)
-{
- while (pos < dataEnd && (*pos == '\t' || *pos == ' '))
- ++pos;
- return pos != dataEnd;
-}
-
-void TextResourceDecoder::checkForBOM(const char* data, size_t len)
-{
- // Check for UTF-16/32 or UTF-8 BOM mark at the beginning, which is a sure sign of a Unicode encoding.
-
- if (m_source == UserChosenEncoding) {
- // FIXME: Maybe a BOM should override even a user-chosen encoding.
- m_checkedForBOM = true;
- return;
- }
-
- // Check if we have enough data.
- size_t bufferLength = m_buffer.size();
- if (bufferLength + len < 4)
- return;
-
- m_checkedForBOM = true;
-
- // Extract the first four bytes.
- // Handle the case where some of bytes are already in the buffer.
- // The last byte is always guaranteed to not be in the buffer.
- const unsigned char* udata = reinterpret_cast<const unsigned char*>(data);
- unsigned char c1 = bufferLength >= 1 ? m_buffer[0] : *udata++;
- unsigned char c2 = bufferLength >= 2 ? m_buffer[1] : *udata++;
- unsigned char c3 = bufferLength >= 3 ? m_buffer[2] : *udata++;
- ASSERT(bufferLength < 4);
- unsigned char c4 = *udata;
-
- // Check for the BOM.
- if (c1 == 0xFF && c2 == 0xFE) {
- if (c3 !=0 || c4 != 0)
- setEncoding(UTF16LittleEndianEncoding(), AutoDetectedEncoding);
- else
- setEncoding(UTF32LittleEndianEncoding(), AutoDetectedEncoding);
- }
- else if (c1 == 0xEF && c2 == 0xBB && c3 == 0xBF)
- setEncoding(UTF8Encoding(), AutoDetectedEncoding);
- else if (c1 == 0xFE && c2 == 0xFF)
- setEncoding(UTF16BigEndianEncoding(), AutoDetectedEncoding);
- else if (c1 == 0 && c2 == 0 && c3 == 0xFE && c4 == 0xFF)
- setEncoding(UTF32BigEndianEncoding(), AutoDetectedEncoding);
-}
-
-bool TextResourceDecoder::checkForCSSCharset(const char* data, size_t len, bool& movedDataToBuffer)
-{
- if (m_source != DefaultEncoding && m_source != EncodingFromParentFrame) {
- m_checkedForCSSCharset = true;
- return true;
- }
-
- size_t oldSize = m_buffer.size();
- m_buffer.grow(oldSize + len);
- memcpy(m_buffer.data() + oldSize, data, len);
-
- movedDataToBuffer = true;
-
- if (m_buffer.size() > 8) { // strlen("@charset") == 8
- const char* dataStart = m_buffer.data();
- const char* dataEnd = dataStart + m_buffer.size();
-
- if (dataStart[0] == '@' && dataStart[1] == 'c' && dataStart[2] == 'h' && dataStart[3] == 'a' && dataStart[4] == 'r' &&
- dataStart[5] == 's' && dataStart[6] == 'e' && dataStart[7] == 't') {
-
- dataStart += 8;
- const char* pos = dataStart;
- if (!skipWhitespace(pos, dataEnd))
- return false;
-
- if (*pos == '"' || *pos == '\'') {
- char quotationMark = *pos;
- ++pos;
- dataStart = pos;
-
- while (pos < dataEnd && *pos != quotationMark)
- ++pos;
- if (pos == dataEnd)
- return false;
-
- int encodingNameLength = pos - dataStart + 1;
-
- ++pos;
- if (!skipWhitespace(pos, dataEnd))
- return false;
-
- if (*pos == ';')
- setEncoding(findTextEncoding(dataStart, encodingNameLength), EncodingFromCSSCharset);
- }
- }
- m_checkedForCSSCharset = true;
- return true;
- }
- return false;
-}
-
-// Other browsers allow comments in the head section, so we need to also.
-// It's important not to look for tags inside the comments.
-static inline void skipComment(const char*& ptr, const char* pEnd)
-{
- const char* p = ptr;
- // Allow <!-->; other browsers do.
- if (*p == '>') {
- p++;
- } else {
- while (p != pEnd) {
- if (*p == '-') {
- // This is the real end of comment, "-->".
- if (p[1] == '-' && p[2] == '>') {
- p += 3;
- break;
- }
- // This is the incorrect end of comment that other browsers allow, "--!>".
- if (p[1] == '-' && p[2] == '!' && p[3] == '>') {
- p += 4;
- break;
- }
- }
- p++;
- }
- }
- ptr = p;
-}
-
-const int bytesToCheckUnconditionally = 1024; // That many input bytes will be checked for meta charset even if <head> section is over.
-
-bool TextResourceDecoder::checkForHeadCharset(const char* data, size_t len, bool& movedDataToBuffer)
-{
- if (m_source != DefaultEncoding && m_source != EncodingFromParentFrame) {
- m_checkedForHeadCharset = true;
- return true;
- }
-
- // This is not completely efficient, since the function might go
- // through the HTML head several times.
-
- size_t oldSize = m_buffer.size();
- m_buffer.grow(oldSize + len);
- memcpy(m_buffer.data() + oldSize, data, len);
-
- movedDataToBuffer = true;
-
- const char* ptr = m_buffer.data();
- const char* pEnd = ptr + m_buffer.size();
-
- // Is there enough data available to check for XML declaration?
- if (m_buffer.size() < 8)
- return false;
-
- // Handle XML declaration, which can have encoding in it. This encoding is honored even for HTML documents.
- // It is an error for an XML declaration not to be at the start of an XML document, and it is ignored in HTML documents in such case.
- if (ptr[0] == '<' && ptr[1] == '?' && ptr[2] == 'x' && ptr[3] == 'm' && ptr[4] == 'l') {
- const char* xmlDeclarationEnd = ptr;
- while (xmlDeclarationEnd != pEnd && *xmlDeclarationEnd != '>')
- ++xmlDeclarationEnd;
- if (xmlDeclarationEnd == pEnd)
- return false;
- // No need for +1, because we have an extra "?" to lose at the end of XML declaration.
- int len;
- int pos = findXMLEncoding(ptr, xmlDeclarationEnd - ptr, len);
- if (pos != -1)
- setEncoding(findTextEncoding(ptr + pos, len), EncodingFromXMLHeader);
- // continue looking for a charset - it may be specified in an HTTP-Equiv meta
- } else if (ptr[0] == '<' && ptr[1] == 0 && ptr[2] == '?' && ptr[3] == 0 && ptr[4] == 'x' && ptr[5] == 0) {
- setEncoding(UTF16LittleEndianEncoding(), AutoDetectedEncoding);
- return true;
- } else if (ptr[0] == 0 && ptr[1] == '<' && ptr[2] == 0 && ptr[3] == '?' && ptr[4] == 0 && ptr[5] == 'x') {
- setEncoding(UTF16BigEndianEncoding(), AutoDetectedEncoding);
- return true;
- } else if (ptr[0] == '<' && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 0 && ptr[4] == '?' && ptr[5] == 0 && ptr[6] == 0 && ptr[7] == 0) {
- setEncoding(UTF32LittleEndianEncoding(), AutoDetectedEncoding);
- return true;
- } else if (ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == '<' && ptr[4] == 0 && ptr[5] == 0 && ptr[6] == 0 && ptr[7] == '?') {
- setEncoding(UTF32BigEndianEncoding(), AutoDetectedEncoding);
- return true;
- }
-
- // we still don't have an encoding, and are in the head
- // the following tags are allowed in <head>:
- // SCRIPT|STYLE|META|LINK|OBJECT|TITLE|BASE
-
- // We stop scanning when a tag that is not permitted in <head>
- // is seen, rather when </head> is seen, because that more closely
- // matches behavior in other browsers; more details in
- // <http://bugs.webkit.org/show_bug.cgi?id=3590>.
-
- // Additionally, we ignore things that looks like tags in <title>, <script> and <noscript>; see
- // <http://bugs.webkit.org/show_bug.cgi?id=4560>, <http://bugs.webkit.org/show_bug.cgi?id=12165>
- // and <http://bugs.webkit.org/show_bug.cgi?id=12389>.
-
- // Since many sites have charset declarations after <body> or other tags that are disallowed in <head>,
- // we don't bail out until we've checked at least bytesToCheckUnconditionally bytes of input.
- // we don't bail out until we've checked at least 2048 bytes of input.
- // TODO(jungshik): Webkit upstream uses 512 bytes, but that seems to be
- // a way too short. IE and Firefox go well beyond that. There might be
- // a performance issue if we make it too large. Ideally, we should run
- // mapreduce to come up with a number to cover 9x% of cases that still
- // does not hurt the performance.
-
- AtomicStringImpl* enclosingTagName = 0;
- bool inHeadSection = true; // Becomes false when </head> or any tag not allowed in head is encountered.
-
- // the HTTP-EQUIV meta has no effect on XHTML
- if (m_contentType == XML)
- return true;
-
- while (ptr + 3 < pEnd) { // +3 guarantees that "<!--" fits in the buffer - and certainly we aren't going to lose any "charset" that way.
- if (*ptr == '<') {
- bool end = false;
- ptr++;
-
- // Handle comments.
- if (ptr[0] == '!' && ptr[1] == '-' && ptr[2] == '-') {
- ptr += 3;
- skipComment(ptr, pEnd);
- if (ptr - m_buffer.data() >= bytesToCheckUnconditionally && !inHeadSection) {
- // Some pages that test bandwidth from within the browser do it by having
- // huge comments and measuring the time they take to load. Repeatedly scanning
- // these comments can take a lot of CPU time.
- m_checkedForHeadCharset = true;
- return true;
- }
- continue;
- }
-
- if (*ptr == '/') {
- ++ptr;
- end = true;
- }
-
- // Grab the tag name, but mostly ignore namespaces.
- bool sawNamespace = false;
- char tagBuffer[20];
- int len = 0;
- while (len < 19) {
- if (ptr == pEnd)
- return false;
- char c = *ptr;
- if (c == ':') {
- len = 0;
- sawNamespace = true;
- ptr++;
- continue;
- }
- if (c >= 'a' && c <= 'z' || c >= '0' && c <= '9')
- ;
- else if (c >= 'A' && c <= 'Z')
- c += 'a' - 'A';
- else
- break;
- tagBuffer[len++] = c;
- ptr++;
- }
- tagBuffer[len] = 0;
- AtomicString tag(tagBuffer);
-
- if (enclosingTagName) {
- if (end && tag.impl() == enclosingTagName)
- enclosingTagName = 0;
- } else {
- if (tag == titleTag)
- enclosingTagName = titleTag.localName().impl();
- else if (tag == scriptTag)
- enclosingTagName = scriptTag.localName().impl();
- else if (tag == noscriptTag)
- enclosingTagName = noscriptTag.localName().impl();
- }
-
- // Find where the opening tag ends.
- const char* tagContentStart = ptr;
- if (!end) {
- while (ptr != pEnd && *ptr != '>') {
- if (*ptr == '\'' || *ptr == '"') {
- char quoteMark = *ptr;
- ++ptr;
- while (ptr != pEnd && *ptr != quoteMark)
- ++ptr;
- if (ptr == pEnd)
- return false;
- }
- ++ptr;
- }
- if (ptr == pEnd)
- return false;
- ++ptr;
- }
-
- if (!end && tag == metaTag && !sawNamespace) {
- const char* str = tagContentStart;
- int length = ptr - tagContentStart;
- int pos = 0;
- while (pos < length) {
- int charsetPos = findIgnoringCase(str + pos, length - pos, "charset");
- if (charsetPos == -1)
- break;
- pos += charsetPos + 7;
- // skip whitespace
- while (pos < length && str[pos] <= ' ')
- pos++;
- if (pos == length)
- break;
- if (str[pos++] != '=')
- continue;
- while (pos < length &&
- (str[pos] <= ' ') || str[pos] == '=' || str[pos] == '"' || str[pos] == '\'')
- pos++;
-
- // end ?
- if (pos == length)
- break;
- int end = pos;
- while (end < length &&
- str[end] != ' ' && str[end] != '"' && str[end] != '\'' &&
- str[end] != ';' && str[end] != '>')
- end++;
- setEncoding(findTextEncoding(str + pos, end - pos), EncodingFromMetaTag);
- if (m_source == EncodingFromMetaTag)
- return true;
-
- if (end >= length || str[end] == '/' || str[end] == '>')
- break;
-
- pos = end + 1;
- }
- } else {
- if (!enclosingTagName && tag != scriptTag && tag != noscriptTag && tag != styleTag
- && tag != linkTag && tag != metaTag && tag != objectTag && tag != titleTag && tag != baseTag
- && (end || tag != htmlTag) && (end || tag != headTag) && isASCIIAlpha(tagBuffer[0])) {
- inHeadSection = false;
- }
-
- if (ptr - m_buffer.data() >= bytesToCheckUnconditionally && !inHeadSection) {
- m_checkedForHeadCharset = true;
- return true;
- }
- }
- } else
- ++ptr;
- }
- return false;
-}
-
-void TextResourceDecoder::detectJapaneseEncoding(const char* data, size_t len)
-{
- switch (KanjiCode::judge(data, len)) {
- case KanjiCode::JIS:
- setEncoding("ISO-2022-JP", AutoDetectedEncoding);
- break;
- case KanjiCode::EUC:
- setEncoding("EUC-JP", AutoDetectedEncoding);
- break;
- case KanjiCode::SJIS:
- setEncoding("Shift_JIS", AutoDetectedEncoding);
- break;
- case KanjiCode::ASCII:
- case KanjiCode::UTF16:
- case KanjiCode::UTF8:
- break;
- }
-}
-
-void TextResourceDecoder::detectEncoding(const char* data, size_t len)
-{
- // need to declare these two vars here to slience gcc's complaint about
- // jumping across variable declarations.
- const UCharsetMatch **matches;
- const char* encoding = NULL;
- int matches_count = 0;
- const char* hint_encoding = m_hintDecoder ? m_hintDecoder->encoding().name() : NULL;
- UErrorCode status = U_ZERO_ERROR;
- UCharsetDetector* detector = ucsdet_open(&status);
- if (U_FAILURE(status))
- return;
- ucsdet_enableInputFilter(detector, true);
- ucsdet_setText(detector, data, static_cast<int32_t>(len), &status);
- if (U_FAILURE(status))
- goto fail;
- // TODO(jungshik) : If we don't manage to open-source our internal
- // detector, use ucsdet_detectAll and pick the most likely one
- // given "the context" (parent-encoding, referrer encoding, etc).
- // We can also 'emulate' Firefox/IE's non-Universal detectors (e.g.
- // Chinese, Japanese, Russian, Korean and Hebrew) by picking the
- // encoding with a highest confidence among the detetctor-specific
- // limited set of candidate encodings. (bug 1202108)
- // Below is the implementation of the first part of what's outlined
- // above.
- matches = ucsdet_detectAll(detector, &matches_count, &status);
- if (U_FAILURE(status))
- goto fail;
- if (hint_encoding) {
- // 10 is the minimum confidence value consistent with the codepoint
- // allocation in a given encoding. The size of a chunk passed to
- // us varies even for the same html file (apparently depending on
- // the network load). When we're given a rather short chunk, we
- // don't have a sufficiently reliable signal other than the fact that
- // the chunk is consistent with a set of encodings. So, instead of
- // setting an arbitrary threshold, we have to scan all the encodings
- // consistent with the data.
- const int32_t kThresold = 10;
- for (int i = 0; i < matches_count; ++i) {
- int32_t confidence = ucsdet_getConfidence(matches[i], &status);
- if (U_FAILURE(status)) {
- status = U_ZERO_ERROR;
- continue;
- }
- if (confidence < kThresold)
- break;
- const char* match_encoding = ucsdet_getName(matches[i], &status);
- if (U_FAILURE(status)) {
- status = U_ZERO_ERROR;
- continue;
- }
- // TODO : Make this comparison even fuzzier to catch cases
- // like ISO-8859-1 and Windows-1252 and ISO-8859-8-I and
- // Windows-1255, ks_c_5601-1987 and EUC-KR. The last case
- // can be worked around comparing canonical names.
- if (!ucnv_compareNames(match_encoding, hint_encoding)) {
- encoding = hint_encoding;
- break;
- }
- }
- }
- // If no match is found so far, just pick the top match.
- // This can happen when a parent frame in EUC-JP refers to
- // a child frame in Shift_JIS although that's not very likely.
- if (!encoding && matches_count > 0)
- encoding = ucsdet_getName(matches[0], &status);
- if (U_SUCCESS(status))
- setEncoding(encoding, AutoDetectedEncoding);
-fail:
- ucsdet_close(detector);
-}
-
-String TextResourceDecoder::decode(const char* data, size_t len)
-{
- if (!m_checkedForBOM)
- checkForBOM(data, len);
-
- bool movedDataToBuffer = false;
-
- if (m_contentType == CSS && !m_checkedForCSSCharset)
- if (!checkForCSSCharset(data, len, movedDataToBuffer))
- return "";
-
- if ((m_contentType == HTML || m_contentType == XML) && !m_checkedForHeadCharset) // HTML and XML
- if (!checkForHeadCharset(data, len, movedDataToBuffer))
- return "";
-
- // Do the auto-detect if our default encoding is one of the Japanese ones.
- // FIXME: It seems wrong to change our encoding downstream after we have already done some decoding.
- // If parent frame does not have specified encoding information and does get its encoding from auto
- // detection, then sub frames should also do encoding auto detection when there are no specified
- // encoding in them.
- if (m_source != UserChosenEncoding && m_source != AutoDetectedEncoding && encoding().isJapanese())
- detectJapaneseEncoding(data, len);
- else if ((m_usesEncodingDetector && m_source == DefaultEncoding) ||
- (m_source == EncodingFromParentFrame && m_hintDecoder &&
- m_hintDecoder->source() == AutoDetectedEncoding))
- detectEncoding(data, len);
-
- ASSERT(encoding().isValid());
-
- if (m_buffer.isEmpty())
- return m_decoder.decode(data, len, false, m_contentType == XML, m_sawError);
-
- if (!movedDataToBuffer) {
- size_t oldSize = m_buffer.size();
- m_buffer.grow(oldSize + len);
- memcpy(m_buffer.data() + oldSize, data, len);
- }
-
- String result = m_decoder.decode(m_buffer.data(), m_buffer.size(), false, m_contentType == XML, m_sawError);
- m_buffer.clear();
- return result;
-}
-
-String TextResourceDecoder::flush()
-{
- // For HTML and XML document, if we can not find proper encoding even
- // document is completely loaded, we need to use automatically detect
- // the encoding of document if user has enabled this option.
- if (m_buffer.size() && !m_checkedForHeadCharset &&
- (m_contentType == HTML || m_contentType == XML) &&
- ((m_usesEncodingDetector && m_source == DefaultEncoding) ||
- (m_source == EncodingFromParentFrame && m_hintDecoder &&
- m_hintDecoder->source() == AutoDetectedEncoding)))
- detectEncoding(m_buffer.data(), m_buffer.size());
-
- String result = m_decoder.decode(m_buffer.data(), m_buffer.size(), true, m_contentType == XML, m_sawError);
- m_buffer.clear();
- return result;
-}
-
-}
diff --git a/webkit/pending/TextResourceDecoder.h b/webkit/pending/TextResourceDecoder.h
deleted file mode 100644
index 476dd21..0000000
--- a/webkit/pending/TextResourceDecoder.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- Copyright (C) 1999 Lars Knoll (knoll@mpi-hd.mpg.de)
- Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
- Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-
-*/
-
-#ifndef TextResourceDecoder_h
-#define TextResourceDecoder_h
-
-#include "TextDecoder.h"
-
-namespace WebCore {
-
-class TextResourceDecoder : public RefCounted<TextResourceDecoder> {
-public:
- enum EncodingSource {
- DefaultEncoding,
- AutoDetectedEncoding,
- EncodingFromXMLHeader,
- EncodingFromMetaTag,
- EncodingFromCSSCharset,
- EncodingFromHTTPHeader,
- UserChosenEncoding,
- EncodingFromParentFrame
- };
-
- static PassRefPtr<TextResourceDecoder> create(const String& mimeType, const TextEncoding& defaultEncoding = TextEncoding(), bool usesEncodingDetector = false, const TextResourceDecoder* hintDecoder = NULL)
- {
- return adoptRef(new TextResourceDecoder(mimeType, defaultEncoding));
- }
- ~TextResourceDecoder();
-
- void setEncoding(const TextEncoding&, EncodingSource);
- const TextEncoding& encoding() const { return m_decoder.encoding(); }
-
- String decode(const char* data, size_t length);
- String flush();
-
- bool sawError() const { return m_sawError; }
-
- EncodingSource source() const { return m_source; }
-
-private:
- TextResourceDecoder(const String& mimeType, const TextEncoding& defaultEncoding, bool usesEncodingDetector = false, const TextResourceDecoder* hintDecoder = NULL);
-
- enum ContentType { PlainText, HTML, XML, CSS }; // PlainText is equivalent to directly using TextDecoder.
- static ContentType determineContentType(const String& mimeType);
- static const TextEncoding& defaultEncoding(ContentType, const TextEncoding& defaultEncoding);
-
- void checkForBOM(const char*, size_t);
- bool checkForCSSCharset(const char*, size_t, bool& movedDataToBuffer);
- bool checkForHeadCharset(const char*, size_t, bool& movedDataToBuffer);
- void detectJapaneseEncoding(const char*, size_t);
- void detectEncoding(const char*, size_t);
-
- ContentType m_contentType;
- TextDecoder m_decoder;
- const TextResourceDecoder* m_hintDecoder;
- EncodingSource m_source;
- Vector<char> m_buffer;
- bool m_checkedForBOM;
- bool m_checkedForCSSCharset;
- bool m_checkedForHeadCharset;
- bool m_sawError;
- bool m_usesEncodingDetector;
-};
-
-}
-
-#endif
diff --git a/webkit/pending/TreeWalker.cpp b/webkit/pending/TreeWalker.cpp
deleted file mode 100644
index 32e4a37..0000000
--- a/webkit/pending/TreeWalker.cpp
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "TreeWalker.h"
-
-#include "ExceptionCode.h"
-#include "ExceptionContext.h"
-#include "Node.h"
-#include "NodeFilter.h"
-#include <wtf/PassRefPtr.h>
-
-namespace WebCore {
-
-TreeWalker::TreeWalker(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
- : Traversal(rootNode, whatToShow, filter, expandEntityReferences)
- , m_current(root())
-{
-}
-
-void TreeWalker::setCurrentNode(PassRefPtr<Node> node, ExceptionCode& ec)
-{
- if (!node) {
- ec = NOT_SUPPORTED_ERR;
- return;
- }
- m_current = node;
-}
-
-inline Node* TreeWalker::setCurrent(PassRefPtr<Node> node)
-{
- m_current = node;
- return m_current.get();
-}
-
-Node* TreeWalker::parentNode(ExceptionContext* exec)
-{
- RefPtr<Node> node = m_current;
- while (node != root()) {
- node = node->parentNode();
- if (!node)
- return 0;
- short acceptNodeResult = acceptNode(exec, node.get());
- if (exec && exec->hadException())
- return 0;
- if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
- return setCurrent(node.release());
- }
- return 0;
-}
-
-Node* TreeWalker::firstChild(ExceptionContext* exec)
-{
- for (RefPtr<Node> node = m_current->firstChild(); node; ) {
- short acceptNodeResult = acceptNode(exec, node.get());
- if (exec && exec->hadException())
- return 0;
- switch (acceptNodeResult) {
- case NodeFilter::FILTER_ACCEPT:
- m_current = node.release();
- return m_current.get();
- case NodeFilter::FILTER_SKIP:
- if (node->firstChild()) {
- node = node->firstChild();
- continue;
- }
- break;
- case NodeFilter::FILTER_REJECT:
- break;
- }
- do {
- if (node->nextSibling()) {
- node = node->nextSibling();
- break;
- }
- Node* parent = node->parentNode();
- if (!parent || parent == root() || parent == m_current)
- return 0;
- node = parent;
- } while (node);
- }
- return 0;
-}
-
-Node* TreeWalker::lastChild(ExceptionContext* exec)
-{
- for (RefPtr<Node> node = m_current->lastChild(); node; ) {
- short acceptNodeResult = acceptNode(exec, node.get());
- if (exec && exec->hadException())
- return 0;
- switch (acceptNodeResult) {
- case NodeFilter::FILTER_ACCEPT:
- m_current = node.release();
- return m_current.get();
- case NodeFilter::FILTER_SKIP:
- if (node->lastChild()) {
- node = node->lastChild();
- continue;
- }
- break;
- case NodeFilter::FILTER_REJECT:
- break;
- }
- do {
- if (node->previousSibling()) {
- node = node->previousSibling();
- break;
- }
- Node* parent = node->parentNode();
- if (!parent || parent == root() || parent == m_current)
- return 0;
- node = parent;
- } while (node);
- }
- return 0;
-}
-
-Node* TreeWalker::previousSibling(ExceptionContext* exec)
-{
- RefPtr<Node> node = m_current;
- if (node == root())
- return 0;
- while (1) {
- for (RefPtr<Node> sibling = node->previousSibling(); sibling; ) {
- short acceptNodeResult = acceptNode(exec, sibling.get());
- if (exec && exec->hadException())
- return 0;
- switch (acceptNodeResult) {
- case NodeFilter::FILTER_ACCEPT:
- m_current = sibling.release();
- return m_current.get();
- case NodeFilter::FILTER_SKIP:
- if (sibling->firstChild()) {
- sibling = sibling->firstChild();
- continue;
- }
- break;
- case NodeFilter::FILTER_REJECT:
- break;
- }
- sibling = sibling->previousSibling();
- }
- node = node->parentNode();
- if (!node || node == root())
- return 0;
- short acceptNodeResult = acceptNode(exec, node.get());
- if (exec && exec->hadException())
- return 0;
- if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
- return 0;
- }
-}
-
-Node* TreeWalker::nextSibling(ExceptionContext* exec)
-{
- RefPtr<Node> node = m_current;
- if (node == root())
- return 0;
- while (1) {
- for (RefPtr<Node> sibling = node->nextSibling(); sibling; ) {
- short acceptNodeResult = acceptNode(exec, sibling.get());
- if (exec && exec->hadException())
- return 0;
- switch (acceptNodeResult) {
- case NodeFilter::FILTER_ACCEPT:
- m_current = sibling.release();
- return m_current.get();
- case NodeFilter::FILTER_SKIP:
- if (sibling->firstChild()) {
- sibling = sibling->firstChild();
- continue;
- }
- break;
- case NodeFilter::FILTER_REJECT:
- break;
- }
- sibling = sibling->nextSibling();
- }
- node = node->parentNode();
- if (!node || node == root())
- return 0;
- short acceptNodeResult = acceptNode(exec, node.get());
- if (exec && exec->hadException())
- return 0;
- if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
- return 0;
- }
-}
-
-Node* TreeWalker::previousNode(ExceptionContext* exec)
-{
- RefPtr<Node> node = m_current;
- while (node != root()) {
- while (Node* previousSibling = node->previousSibling()) {
- node = previousSibling;
- short acceptNodeResult = acceptNode(exec, node.get());
- if (exec && exec->hadException())
- return 0;
- if (acceptNodeResult == NodeFilter::FILTER_REJECT)
- continue;
- while (Node* lastChild = node->lastChild()) {
- node = lastChild;
- acceptNodeResult = acceptNode(exec, node.get());
- if (exec && exec->hadException())
- return 0;
- if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
- continue;
- }
- if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) {
- m_current = node.release();
- return m_current.get();
- }
- }
- if (node == root())
- return 0;
- Node* parent = node->parentNode();
- if (!parent)
- return 0;
- node = parent;
- short acceptNodeResult = acceptNode(exec, node.get());
- if (exec && exec->hadException())
- return 0;
- if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
- return setCurrent(node.release());
- }
- return 0;
-}
-
-Node* TreeWalker::nextNode(ExceptionContext* exec)
-{
- RefPtr<Node> node = m_current;
-Children:
- while (Node* firstChild = node->firstChild()) {
- node = firstChild;
- short acceptNodeResult = acceptNode(exec, node.get());
- if (exec && exec->hadException())
- return 0;
- if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
- return setCurrent(node.release());
- if (acceptNodeResult == NodeFilter::FILTER_REJECT)
- break;
- }
- while (Node* nextSibling = node->traverseNextSibling(root())) {
- node = nextSibling;
- short acceptNodeResult = acceptNode(exec, node.get());
- if (exec && exec->hadException())
- return 0;
- if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
- return setCurrent(node.release());
- if (acceptNodeResult == NodeFilter::FILTER_SKIP)
- goto Children;
- }
- return 0;
-}
-
-Node* TreeWalker::parentNode()
-{
- ExceptionContext context(m_current.get());
- return parentNode(&context);
-}
-
-Node* TreeWalker::firstChild()
-{
- ExceptionContext context(m_current.get());
- return firstChild(&context);
-}
-
-Node* TreeWalker::lastChild()
-{
- ExceptionContext context(m_current.get());
- return lastChild(&context);
-}
-
-Node* TreeWalker::previousSibling()
-{
- ExceptionContext context(m_current.get());
- return previousSibling(&context);
-}
-
-Node* TreeWalker::nextSibling()
-{
- ExceptionContext context(m_current.get());
- return nextSibling(&context);
-}
-
-Node* TreeWalker::previousNode()
-{
- ExceptionContext context(m_current.get());
- return previousNode(&context);
-}
-
-Node* TreeWalker::nextNode()
-{
- ExceptionContext context(m_current.get());
- return nextNode(&context);
-}
-
-} // namespace WebCore
diff --git a/webkit/pending/TreeWalker.h b/webkit/pending/TreeWalker.h
deleted file mode 100644
index 5cc5f25..0000000
--- a/webkit/pending/TreeWalker.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
- * Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef TreeWalker_h
-#define TreeWalker_h
-
-#include "ExceptionContext.h"
-#include "NodeFilter.h"
-#include "Traversal.h"
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-
-namespace WebCore {
-
- typedef int ExceptionCode;
-
- class TreeWalker : public RefCounted<TreeWalker>, public Traversal {
- public:
- static PassRefPtr<TreeWalker> create(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
- {
- return adoptRef(new TreeWalker(rootNode, whatToShow, filter, expandEntityReferences));
- }
-
- Node* currentNode() const { return m_current.get(); }
- void setCurrentNode(PassRefPtr<Node>, ExceptionCode&);
-
- Node* parentNode(ExceptionContext*);
- Node* firstChild(ExceptionContext*);
- Node* lastChild(ExceptionContext*);
- Node* previousSibling(ExceptionContext*);
- Node* nextSibling(ExceptionContext*);
- Node* previousNode(ExceptionContext*);
- Node* nextNode(ExceptionContext*);
-
- // For non-JS bindings. Silently ignores the JavaScript exception if any.
- Node* parentNode();
- Node* firstChild();
- Node* lastChild();
- Node* previousSibling();
- Node* nextSibling();
- Node* previousNode();
- Node* nextNode();
-
- private:
- TreeWalker(PassRefPtr<Node>, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences);
-
- Node* setCurrent(PassRefPtr<Node>);
-
- RefPtr<Node> m_current;
- };
-
-} // namespace WebCore
-
-#endif // TreeWalker_h
diff --git a/webkit/pending/XMLHttpRequest.cpp b/webkit/pending/XMLHttpRequest.cpp
deleted file mode 100644
index 7dc5c4c..0000000
--- a/webkit/pending/XMLHttpRequest.cpp
+++ /dev/null
@@ -1,1381 +0,0 @@
-/*
- * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org>
- * Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "config.h"
-#include "XMLHttpRequest.h"
-
-#include "CString.h"
-#include "Console.h"
-#include "DOMImplementation.h"
-#include "DOMWindow.h"
-#include "Event.h"
-#include "EventException.h"
-#include "EventListener.h"
-#include "EventNames.h"
-#include "File.h"
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "HTTPParsers.h"
-#include "InspectorController.h"
-#include "KURL.h"
-#include "KURLHash.h"
-#include "Page.h"
-#include "Settings.h"
-#include "SubresourceLoader.h"
-#include "SystemTime.h"
-#include "TextResourceDecoder.h"
-#include "XMLHttpRequestException.h"
-#include "XMLHttpRequestProgressEvent.h"
-#include "XMLHttpRequestUpload.h"
-#include "markup.h"
-
-#if USE(JSC)
-#include <kjs/protect.h>
-#include "JSDOMBinding.h"
-#endif
-
-#include "base/stats_counters.h"
-
-namespace WebCore {
-
-using namespace EventNames;
-
-struct PreflightResultCacheItem {
- PreflightResultCacheItem(unsigned expiryDelta, bool credentials, HashSet<String>* methods, HashSet<String, CaseFoldingHash>* headers)
- : m_absoluteExpiryTime(currentTime() + expiryDelta)
- , m_credentials(credentials)
- , m_methods(methods)
- , m_headers(headers)
- {
- }
-
- // FIXME: A better solution to holding onto the absolute expiration time might be
- // to start a timer for the expiration delta, that removes this from the cache when
- // it fires.
- double m_absoluteExpiryTime;
- bool m_credentials;
- OwnPtr<HashSet<String> > m_methods;
- OwnPtr<HashSet<String, CaseFoldingHash> > m_headers;
-};
-
-typedef HashMap<std::pair<String, KURL>, PreflightResultCacheItem*> PreflightResultCache;
-
-static PreflightResultCache& preflightResultCache()
-{
- static PreflightResultCache cache;
- return cache;
-}
-
-static void appendPreflightResultCacheEntry(String origin, KURL url, unsigned expiryDelta,
- bool credentials, HashSet<String>* methods, HashSet<String, CaseFoldingHash>* headers)
-{
- ASSERT(!preflightResultCache().contains(std::make_pair(origin, url)));
-
- PreflightResultCacheItem* item = new PreflightResultCacheItem(expiryDelta, credentials, methods, headers);
- preflightResultCache().set(std::make_pair(origin, url), item);
-}
-
-typedef HashSet<XMLHttpRequest*> RequestsSet;
-
-static HashMap<Document*, RequestsSet*>& requestsByDocument()
-{
- static HashMap<Document*, RequestsSet*> map;
- return map;
-}
-
-static void addToRequestsByDocument(Document* doc, XMLHttpRequest* req)
-{
- ASSERT(doc);
- ASSERT(req);
-
- RequestsSet* requests = requestsByDocument().get(doc);
- if (!requests) {
- requests = new RequestsSet;
- requestsByDocument().set(doc, requests);
- }
-
- ASSERT(!requests->contains(req));
- requests->add(req);
-}
-
-static void removeFromRequestsByDocument(Document* doc, XMLHttpRequest* req)
-{
- ASSERT(doc);
- ASSERT(req);
-
- RequestsSet* requests = requestsByDocument().get(doc);
- ASSERT(requests);
- ASSERT(requests->contains(req));
- requests->remove(req);
- if (requests->isEmpty()) {
- requestsByDocument().remove(doc);
- delete requests;
- }
-}
-
-static bool isSafeRequestHeader(const String& name)
-{
- static HashSet<String, CaseFoldingHash> forbiddenHeaders;
- static String proxyString("proxy-");
- static String secString("sec-");
-
- if (forbiddenHeaders.isEmpty()) {
- forbiddenHeaders.add("accept-charset");
- forbiddenHeaders.add("accept-encoding");
- forbiddenHeaders.add("connection");
- forbiddenHeaders.add("content-length");
- forbiddenHeaders.add("content-transfer-encoding");
- forbiddenHeaders.add("date");
- forbiddenHeaders.add("expect");
- forbiddenHeaders.add("host");
- forbiddenHeaders.add("keep-alive");
- forbiddenHeaders.add("referer");
- forbiddenHeaders.add("te");
- forbiddenHeaders.add("trailer");
- forbiddenHeaders.add("transfer-encoding");
- forbiddenHeaders.add("upgrade");
- forbiddenHeaders.add("via");
- }
-
- return !forbiddenHeaders.contains(name) && !name.startsWith(proxyString, false) &&
- !name.startsWith(secString, false);
-}
-
-static bool isOnAccessControlSimpleRequestHeaderWhitelist(const String& name)
-{
- return equalIgnoringCase(name, "accept") || equalIgnoringCase(name, "accept-language") || equalIgnoringCase(name, "content-type");
-}
-
-static bool isOnAccessControlResponseHeaderWhitelist(const String& name)
-{
- static HashSet<String, CaseFoldingHash> allowedHeaders;
- if (allowedHeaders.isEmpty()) {
- allowedHeaders.add("cache-control");
- allowedHeaders.add("content-language");
- allowedHeaders.add("content-type");
- allowedHeaders.add("expires");
- allowedHeaders.add("last-modified");
- allowedHeaders.add("pragma");
- }
-
- return allowedHeaders.contains(name);
-}
-
-// Determines if a string is a valid token, as defined by
-// "token" in section 2.2 of RFC 2616.
-static bool isValidToken(const String& name)
-{
- unsigned length = name.length();
- for (unsigned i = 0; i < length; i++) {
- UChar c = name[i];
-
- if (c >= 127 || c <= 32)
- return false;
-
- if (c == '(' || c == ')' || c == '<' || c == '>' || c == '@' ||
- c == ',' || c == ';' || c == ':' || c == '\\' || c == '\"' ||
- c == '/' || c == '[' || c == ']' || c == '?' || c == '=' ||
- c == '{' || c == '}')
- return false;
- }
-
- return true;
-}
-
-static bool isValidHeaderValue(const String& name)
-{
- // FIXME: This should really match name against
- // field-value in section 4.2 of RFC 2616.
-
- return !name.contains('\r') && !name.contains('\n');
-}
-
-XMLHttpRequest::XMLHttpRequest(Document* doc)
- : m_doc(doc)
- , m_async(true)
- , m_includeCredentials(false)
- , m_state(UNSENT)
- , m_identifier(std::numeric_limits<unsigned long>::max())
- , m_responseText("")
- , m_createdDocument(false)
- , m_error(false)
- , m_uploadComplete(false)
- , m_sameOriginRequest(true)
- , m_inPreflight(false)
- , m_receivedLength(0)
-{
- ASSERT(m_doc);
- addToRequestsByDocument(m_doc, this);
-}
-
-XMLHttpRequest::~XMLHttpRequest()
-{
- if (m_doc)
- removeFromRequestsByDocument(m_doc, this);
-
- if (m_upload)
- m_upload->disconnectXMLHttpRequest();
-}
-
-XMLHttpRequest::State XMLHttpRequest::readyState() const
-{
- return m_state;
-}
-
-const JSString& XMLHttpRequest::responseText() const
-{
- return m_responseText;
-}
-
-Document* XMLHttpRequest::responseXML() const
-{
- if (m_state != DONE)
- return 0;
-
- if (!m_createdDocument) {
- if (m_response.isHTTP() && !responseIsXML()) {
- // The W3C spec requires this.
- m_responseXML = 0;
- } else {
- m_responseXML = m_doc->implementation()->createDocument(0);
- m_responseXML->open();
- m_responseXML->setURL(m_url);
- // FIXME: set Last-Modified and cookies (currently, those are only available for HTMLDocuments).
- m_responseXML->write(String(m_responseText));
- m_responseXML->finishParsing();
- m_responseXML->close();
-
- if (!m_responseXML->wellFormed())
- m_responseXML = 0;
- }
- m_createdDocument = true;
- }
-
- return m_responseXML.get();
-}
-
-XMLHttpRequestUpload* XMLHttpRequest::upload()
-{
- if (!m_upload)
- m_upload = XMLHttpRequestUpload::create(this);
- return m_upload.get();
-}
-
-void XMLHttpRequest::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> eventListener, bool)
-{
- EventListenersMap::iterator iter = m_eventListeners.find(eventType.impl());
- if (iter == m_eventListeners.end()) {
- ListenerVector listeners;
- listeners.append(eventListener);
- m_eventListeners.add(eventType.impl(), listeners);
- } else {
- ListenerVector& listeners = iter->second;
- for (ListenerVector::iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter)
- if (*listenerIter == eventListener)
- return;
-
- listeners.append(eventListener);
- m_eventListeners.add(eventType.impl(), listeners);
- }
-}
-
-void XMLHttpRequest::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool)
-{
- EventListenersMap::iterator iter = m_eventListeners.find(eventType.impl());
- if (iter == m_eventListeners.end())
- return;
-
- ListenerVector& listeners = iter->second;
- for (ListenerVector::const_iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter)
- if (*listenerIter == eventListener) {
- listeners.remove(listenerIter - listeners.begin());
- return;
- }
-}
-
-bool XMLHttpRequest::dispatchEvent(PassRefPtr<Event> evt, ExceptionCode& ec, bool /*tempEvent*/)
-{
- // FIXME: check for other error conditions enumerated in the spec.
- if (evt->type().isEmpty()) {
- ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
- return true;
- }
-
- ListenerVector listenersCopy = m_eventListeners.get(evt->type().impl());
- for (ListenerVector::const_iterator listenerIter = listenersCopy.begin(); listenerIter != listenersCopy.end(); ++listenerIter) {
- evt->setTarget(this);
- evt->setCurrentTarget(this);
- listenerIter->get()->handleEvent(evt.get(), false);
- }
-
- return !evt->defaultPrevented();
-}
-
-void XMLHttpRequest::changeState(State newState)
-{
- if (m_state != newState) {
- m_state = newState;
- callReadyStateChangeListener();
- }
-}
-
-void XMLHttpRequest::callReadyStateChangeListener()
-{
- if (!m_doc || !m_doc->frame())
- return;
-
- dispatchReadyStateChangeEvent();
-
- if (m_state == DONE)
- dispatchLoadEvent();
-}
-
-void XMLHttpRequest::open(const String& method, const KURL& url, bool async, ExceptionCode& ec)
-{
- internalAbort();
- State previousState = m_state;
- m_state = UNSENT;
- m_error = false;
-
- m_uploadComplete = false;
-
- // clear stuff from possible previous load
- clearResponse();
- clearRequest();
-
- ASSERT(m_state == UNSENT);
-
- if (!isValidToken(method)) {
- ec = SYNTAX_ERR;
- return;
- }
-
- // Method names are case sensitive. But since Firefox uppercases method names it knows, we'll do the same.
- String methodUpper(method.upper());
-
- if (methodUpper == "TRACE" || methodUpper == "TRACK" || methodUpper == "CONNECT") {
- ec = SECURITY_ERR;
- return;
- }
-
- m_url = url;
-
- if (methodUpper == "COPY" || methodUpper == "DELETE" || methodUpper == "GET" || methodUpper == "HEAD"
- || methodUpper == "INDEX" || methodUpper == "LOCK" || methodUpper == "M-POST" || methodUpper == "MKCOL" || methodUpper == "MOVE"
- || methodUpper == "OPTIONS" || methodUpper == "POST" || methodUpper == "PROPFIND" || methodUpper == "PROPPATCH" || methodUpper == "PUT"
- || methodUpper == "UNLOCK")
- m_method = methodUpper;
- else
- m_method = method;
-
- m_async = async;
-
- ASSERT(!m_loader);
-
- // Check previous state to avoid dispatching readyState event
- // when calling open several times in a row.
- if (previousState != OPENED)
- changeState(OPENED);
- else
- m_state = OPENED;
-}
-
-void XMLHttpRequest::open(const String& method, const KURL& url, bool async, const String& user, ExceptionCode& ec)
-{
- KURL urlWithCredentials(url);
- urlWithCredentials.setUser(user);
-
- open(method, urlWithCredentials, async, ec);
-}
-
-void XMLHttpRequest::open(const String& method, const KURL& url, bool async, const String& user, const String& password, ExceptionCode& ec)
-{
- KURL urlWithCredentials(url);
- urlWithCredentials.setUser(user);
- urlWithCredentials.setPass(password);
-
- open(method, urlWithCredentials, async, ec);
-}
-
-bool XMLHttpRequest::initSend(ExceptionCode& ec)
-{
- if (!m_doc)
- return false;
-
- if (m_state != OPENED || m_loader) {
- ec = INVALID_STATE_ERR;
- return false;
- }
-
- m_error = false;
- return true;
-}
-
-void XMLHttpRequest::send(ExceptionCode& ec)
-{
- send(String(), ec);
-}
-
-void XMLHttpRequest::send(Document* document, ExceptionCode& ec)
-{
- ASSERT(document);
-
- if (!initSend(ec))
- return;
-
- if (m_method != "GET" && m_method != "HEAD" && (m_url.protocolIs("http") || m_url.protocolIs("https"))) {
- String contentType = getRequestHeader("Content-Type");
- if (contentType.isEmpty()) {
-#if ENABLE(DASHBOARD_SUPPORT)
- Settings* settings = m_doc->settings();
- if (settings && settings->usesDashboardBackwardCompatibilityMode())
- setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded");
- else
-#endif
- // FIXME: this should include the charset used for encoding.
- setRequestHeaderInternal("Content-Type", "application/xml");
- }
-
- // FIXME: According to XMLHttpRequest Level 2, this should use the Document.innerHTML algorithm
- // from the HTML5 specification to serialize the document.
- String body = createMarkup(document);
-
- // FIXME: this should use value of document.inputEncoding to determine the encoding to use.
- TextEncoding encoding = UTF8Encoding();
- m_requestEntityBody = FormData::create(encoding.encode(body.characters(), body.length(), EntitiesForUnencodables));
- if (m_upload)
- m_requestEntityBody->setAlwaysStream(true);
- }
-
- createRequest(ec);
-}
-
-void XMLHttpRequest::send(const String& body, ExceptionCode& ec)
-{
- if (!initSend(ec))
- return;
-
- if (!body.isNull() && m_method != "GET" && m_method != "HEAD" && (m_url.protocolIs("http") || m_url.protocolIs("https"))) {
- String contentType = getRequestHeader("Content-Type");
- if (contentType.isEmpty()) {
-#if ENABLE(DASHBOARD_SUPPORT)
- Settings* settings = m_doc->settings();
- if (settings && settings->usesDashboardBackwardCompatibilityMode())
- setRequestHeaderInternal("Content-Type", "application/x-www-form-urlencoded");
- else
-#endif
- setRequestHeaderInternal("Content-Type", "application/xml");
- }
-
- m_requestEntityBody = FormData::create(UTF8Encoding().encode(body.characters(), body.length(), EntitiesForUnencodables));
- if (m_upload)
- m_requestEntityBody->setAlwaysStream(true);
- }
-
- createRequest(ec);
-}
-
-void XMLHttpRequest::send(File* body, ExceptionCode& ec)
-{
- if (!initSend(ec))
- return;
-
- if (m_method != "GET" && m_method != "HEAD" && (m_url.protocolIs("http") || m_url.protocolIs("https"))) {
- // FIXME: Should we set a Content-Type if one is not set.
- // FIXME: add support for uploading bundles.
- m_requestEntityBody = FormData::create();
- m_requestEntityBody->appendFile(body->path(), false);
- }
-
- createRequest(ec);
-}
-
-void XMLHttpRequest::createRequest(ExceptionCode& ec)
-{
- if (m_async) {
- dispatchLoadStartEvent();
- if (m_requestEntityBody && m_upload)
- m_upload->dispatchLoadStartEvent();
- }
-
- m_sameOriginRequest = m_doc->securityOrigin()->canRequest(m_url);
-
- if (!m_sameOriginRequest) {
- makeCrossSiteAccessRequest(ec);
- return;
- }
-
- makeSameOriginRequest(ec);
-}
-
-void XMLHttpRequest::makeSameOriginRequest(ExceptionCode& ec)
-{
- ASSERT(m_sameOriginRequest);
-
- ResourceRequest request(m_url);
- request.setHTTPMethod(m_method);
-
- if (m_requestEntityBody) {
- ASSERT(m_method != "GET");
- request.setHTTPBody(m_requestEntityBody.release());
- }
-
- if (m_requestHeaders.size() > 0)
- request.addHTTPHeaderFields(m_requestHeaders);
-
- if (m_async)
- loadRequestAsynchronously(request);
- else
- loadRequestSynchronously(request, ec);
-}
-
-bool XMLHttpRequest::isSimpleCrossSiteAccessRequest() const
-{
- if (m_method != "GET" && m_method != "POST")
- return false;
-
- HTTPHeaderMap::const_iterator end = m_requestHeaders.end();
- for (HTTPHeaderMap::const_iterator it = m_requestHeaders.begin(); it != end; ++it) {
- if (!isOnAccessControlSimpleRequestHeaderWhitelist(it->first))
- return false;
- }
-
- return true;
-}
-
-void XMLHttpRequest::makeCrossSiteAccessRequest(ExceptionCode& ec)
-{
- ASSERT(!m_sameOriginRequest);
-
- if (isSimpleCrossSiteAccessRequest())
- makeSimpleCrossSiteAccessRequest(ec);
- else
- makeCrossSiteAccessRequestWithPreflight(ec);
-}
-
-String XMLHttpRequest::accessControlOrigin() const
-{
- String accessControlOrigin = m_doc->securityOrigin()->toString();
- if (accessControlOrigin.isEmpty())
- return "null";
- return accessControlOrigin;
-}
-
-void XMLHttpRequest::makeSimpleCrossSiteAccessRequest(ExceptionCode& ec)
-{
- ASSERT(isSimpleCrossSiteAccessRequest());
-
- KURL url = m_url;
- url.setUser(String());
- url.setPass(String());
-
- ResourceRequest request(url);
- request.setHTTPMethod(m_method);
- request.setAllowHTTPCookies(m_includeCredentials);
- request.setHTTPHeaderField("Origin", accessControlOrigin());
-
- if (m_requestHeaders.size() > 0)
- request.addHTTPHeaderFields(m_requestHeaders);
-
- if (m_async)
- loadRequestAsynchronously(request);
- else
- loadRequestSynchronously(request, ec);
-}
-
-static bool canSkipPrelight(PreflightResultCache::iterator cacheIt, bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders)
-{
- PreflightResultCacheItem* item = cacheIt->second;
- if (item->m_absoluteExpiryTime < currentTime())
- return false;
- if (includeCredentials && !item->m_credentials)
- return false;
- if (!item->m_methods->contains(method) && method != "GET" && method != "POST")
- return false;
- HTTPHeaderMap::const_iterator end = requestHeaders.end();
- for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) {
- if (!item->m_headers->contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first))
- return false;
- }
-
- return true;
-}
-
-void XMLHttpRequest::makeCrossSiteAccessRequestWithPreflight(ExceptionCode& ec)
-{
- String origin = accessControlOrigin();
- KURL url = m_url;
- url.setUser(String());
- url.setPass(String());
-
- bool skipPreflight = false;
-
- PreflightResultCache::iterator cacheIt = preflightResultCache().find(std::make_pair(origin, url));
- if (cacheIt != preflightResultCache().end()) {
- skipPreflight = canSkipPrelight(cacheIt, m_includeCredentials, m_method, m_requestHeaders);
- if (!skipPreflight) {
- delete cacheIt->second;
- preflightResultCache().remove(cacheIt);
- }
- }
-
- if (!skipPreflight) {
- m_inPreflight = true;
- ResourceRequest preflightRequest(url);
- preflightRequest.setHTTPMethod("OPTIONS");
- preflightRequest.setHTTPHeaderField("Origin", origin);
- preflightRequest.setHTTPHeaderField("Access-Control-Request-Method", m_method);
-
- if (m_requestHeaders.size() > 0) {
- Vector<UChar> headerBuffer;
- HTTPHeaderMap::const_iterator it = m_requestHeaders.begin();
- append(headerBuffer, it->first);
- ++it;
-
- HTTPHeaderMap::const_iterator end = m_requestHeaders.end();
- for (; it != end; ++it) {
- headerBuffer.append(',');
- headerBuffer.append(' ');
- append(headerBuffer, it->first);
- }
-
- preflightRequest.setHTTPHeaderField("Access-Control-Request-Headers", String::adopt(headerBuffer));
- preflightRequest.addHTTPHeaderFields(m_requestHeaders);
- }
-
- if (m_async) {
- loadRequestAsynchronously(preflightRequest);
- return;
- }
-
- loadRequestSynchronously(preflightRequest, ec);
- m_inPreflight = false;
-
- if (ec)
- return;
- }
-
- // Send the actual request.
- ResourceRequest request(url);
- request.setHTTPMethod(m_method);
- request.setAllowHTTPCookies(m_includeCredentials);
- request.setHTTPHeaderField("Origin", origin);
-
- if (m_requestHeaders.size() > 0)
- request.addHTTPHeaderFields(m_requestHeaders);
-
- if (m_requestEntityBody) {
- ASSERT(m_method != "GET");
- request.setHTTPBody(m_requestEntityBody.release());
- }
-
- if (m_async) {
- loadRequestAsynchronously(request);
- return;
- }
-
- loadRequestSynchronously(request, ec);
-}
-
-void XMLHttpRequest::handleAsynchronousPreflightResult()
-{
- ASSERT(m_inPreflight);
- ASSERT(m_async);
-
- m_inPreflight = false;
-
- KURL url = m_url;
- url.setUser(String());
- url.setPass(String());
-
- ResourceRequest request(url);
- request.setHTTPMethod(m_method);
- request.setAllowHTTPCookies(m_includeCredentials);
- request.setHTTPHeaderField("Origin", accessControlOrigin());
-
- if (m_requestHeaders.size() > 0)
- request.addHTTPHeaderFields(m_requestHeaders);
-
- if (m_requestEntityBody) {
- ASSERT(m_method != "GET");
- request.setHTTPBody(m_requestEntityBody.release());
- }
-
- loadRequestAsynchronously(request);
-}
-
-void XMLHttpRequest::loadRequestSynchronously(ResourceRequest& request, ExceptionCode& ec)
-{
- ASSERT(!m_async);
- Vector<char> data;
- ResourceError error;
- ResourceResponse response;
-
- if (m_doc->frame())
- m_identifier = m_doc->frame()->loader()->loadResourceSynchronously(request, error, response, data);
-
- m_loader = 0;
-
- // No exception for file:/// resources, see <rdar://problem/4962298>.
- // Also, if we have an HTTP response, then it wasn't a network error in fact.
- if (error.isNull() || request.url().isLocalFile() || response.httpStatusCode() > 0) {
- processSyncLoadResults(data, response, ec);
- return;
- }
-
- if (error.isCancellation()) {
- abortError();
- ec = XMLHttpRequestException::ABORT_ERR;
- return;
- }
-
- if (error.isCancellation()) {
- abortError();
- ec = XMLHttpRequestException::ABORT_ERR;
- return;
- }
-
- networkError();
- ec = XMLHttpRequestException::NETWORK_ERR;
-}
-
-
-void XMLHttpRequest::loadRequestAsynchronously(ResourceRequest& request)
-{
- ASSERT(m_async);
- // SubresourceLoader::create can return null here, for example if we're no longer attached to a page.
- // This is true while running onunload handlers.
- // FIXME: We need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>.
- // FIXME: Maybe create can return null for other reasons too?
- // We need to keep content sniffing enabled for local files due to CFNetwork not providing a MIME type
- // for local files otherwise, <rdar://problem/5671813>.
- bool sendResourceLoadCallbacks = !m_inPreflight;
- m_loader = SubresourceLoader::create(m_doc->frame(), this, request, false, sendResourceLoadCallbacks, request.url().isLocalFile());
-
- if (m_loader) {
- // Neither this object nor the JavaScript wrapper should be deleted while
- // a request is in progress because we need to keep the listeners alive,
- // and they are referenced by the JavaScript wrapper.
- ref();
-
-#if USE(JSC)
- KJS::gcProtectNullTolerant(ScriptInterpreter::getDOMObject(this));
-#elif USE(V8)
- ScriptController::gcProtectJSWrapper(this);
-#endif
- }
-}
-
-void XMLHttpRequest::abort()
-{
- bool sendFlag = m_loader;
-
- internalAbort();
-
- // Clear headers as required by the spec
- m_requestHeaders.clear();
-
- if ((m_state <= OPENED && !sendFlag) || m_state == DONE)
- m_state = UNSENT;
- else {
- ASSERT(!m_loader);
- changeState(DONE);
- m_state = UNSENT;
- }
-
- dispatchAbortEvent();
- if (!m_uploadComplete) {
- m_uploadComplete = true;
- if (m_upload)
- m_upload->dispatchAbortEvent();
- }
-}
-
-void XMLHttpRequest::internalAbort()
-{
- bool hadLoader = m_loader;
-
- m_error = true;
-
- // FIXME: when we add the support for multi-part XHR, we will have to think be careful with this initialization.
- m_receivedLength = 0;
-
- if (hadLoader) {
- m_loader->cancel();
- m_loader = 0;
- }
-
- m_decoder = 0;
-
- if (hadLoader)
- dropProtection();
-}
-
-void XMLHttpRequest::clearResponse()
-{
- m_response = ResourceResponse();
- m_responseText = "";
- m_createdDocument = false;
- m_responseXML = 0;
-}
-
-void XMLHttpRequest::clearRequest()
-{
- m_requestHeaders.clear();
- m_requestEntityBody = 0;
-}
-
-void XMLHttpRequest::genericError()
-{
- clearResponse();
- clearRequest();
- m_error = true;
-
- // The spec says we should "Synchronously switch the state to DONE." and then "Synchronously dispatch a readystatechange event on the object"
- // but this does not match Firefox.
-}
-
-void XMLHttpRequest::networkError()
-{
- genericError();
- dispatchErrorEvent();
- if (!m_uploadComplete) {
- m_uploadComplete = true;
- if (m_upload)
- m_upload->dispatchErrorEvent();
- }
-}
-
-void XMLHttpRequest::abortError()
-{
- genericError();
- dispatchAbortEvent();
- if (!m_uploadComplete) {
- m_uploadComplete = true;
- if (m_upload)
- m_upload->dispatchAbortEvent();
- }
-}
-
-void XMLHttpRequest::dropProtection()
-{
-#if USE(JSC)
- // The XHR object itself holds on to the responseText, and
- // thus has extra cost even independent of any
- // responseText or responseXML objects it has handed
- // out. But it is protected from GC while loading, so this
- // can't be recouped until the load is done, so only
- // report the extra cost at that point.
-
- KJS::JSValue* wrapper = ScriptInterpreter::getDOMObject(this);
- if (wrapper) {
- KJS::gcUnprotect(wrapper);
- KJS::Heap::heap(wrapper)->reportExtraMemoryCost(m_responseText.size() * 2);
- KJS::JSValue* wrapper = ScriptInterpreter::getDOMObject(this);
- }
-#elif USE(V8)
- ScriptController::gcUnprotectJSWrapper(this);
-#endif
-
- deref();
-}
-
-void XMLHttpRequest::overrideMimeType(const String& override)
-{
- m_mimeTypeOverride = override;
-}
-
-void XMLHttpRequest::setRequestHeader(const String& name, const String& value, ExceptionCode& ec)
-{
- if (m_state != OPENED || m_loader) {
-#if ENABLE(DASHBOARD_SUPPORT)
- Settings* settings = m_doc ? m_doc->settings() : 0;
- if (settings && settings->usesDashboardBackwardCompatibilityMode())
- return;
-#endif
-
- ec = INVALID_STATE_ERR;
- return;
- }
-
- if (!isValidToken(name) || !isValidHeaderValue(value)) {
- ec = SYNTAX_ERR;
- return;
- }
-
- // A privileged script (e.g. a Dashboard widget) can set any headers.
- if (!m_doc->securityOrigin()->canLoadLocalResources() && !isSafeRequestHeader(name)) {
- if (m_doc && m_doc->frame())
- m_doc->frame()->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, "Refused to set unsafe header \"" + name + "\"", 1, String());
- return;
- }
-
- setRequestHeaderInternal(name, value);
-}
-
-void XMLHttpRequest::setRequestHeaderInternal(const String& name, const String& value)
-{
- pair<HTTPHeaderMap::iterator, bool> result = m_requestHeaders.add(name, value);
- if (!result.second)
- result.first->second += ", " + value;
-}
-
-String XMLHttpRequest::getRequestHeader(const String& name) const
-{
- return m_requestHeaders.get(name);
-}
-
-String XMLHttpRequest::getAllResponseHeaders(ExceptionCode& ec) const
-{
- if (m_state < LOADING) {
- ec = INVALID_STATE_ERR;
- return "";
- }
-
- Vector<UChar> stringBuilder;
- String separator(": ");
-
- HTTPHeaderMap::const_iterator end = m_response.httpHeaderFields().end();
- for (HTTPHeaderMap::const_iterator it = m_response.httpHeaderFields().begin(); it!= end; ++it) {
- if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(it->first))
- continue;
-
- stringBuilder.append(it->first.characters(), it->first.length());
- stringBuilder.append(separator.characters(), separator.length());
- stringBuilder.append(it->second.characters(), it->second.length());
- stringBuilder.append((UChar)'\r');
- stringBuilder.append((UChar)'\n');
- }
-
- return String::adopt(stringBuilder);
-}
-
-String XMLHttpRequest::getResponseHeader(const String& name, ExceptionCode& ec) const
-{
- if (m_state < LOADING) {
- ec = INVALID_STATE_ERR;
- return "";
- }
-
- if (!isValidToken(name))
- return "";
-
- if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name))
- return "";
-
- return m_response.httpHeaderField(name);
-}
-
-String XMLHttpRequest::responseMIMEType() const
-{
- String mimeType = extractMIMETypeFromMediaType(m_mimeTypeOverride);
- if (mimeType.isEmpty()) {
- if (m_response.isHTTP())
- mimeType = extractMIMETypeFromMediaType(m_response.httpHeaderField("Content-Type"));
- else
- mimeType = m_response.mimeType();
- }
- if (mimeType.isEmpty())
- mimeType = "text/xml";
-
- return mimeType;
-}
-
-bool XMLHttpRequest::responseIsXML() const
-{
- return DOMImplementation::isXMLMIMEType(responseMIMEType());
-}
-
-int XMLHttpRequest::status(ExceptionCode& ec) const
-{
- if (m_response.httpStatusCode())
- return m_response.httpStatusCode();
-
- if (m_state == OPENED) {
- // Firefox only raises an exception in this state; we match it.
- // Note the case of local file requests, where we have no HTTP response code! Firefox never raises an exception for those, but we match HTTP case for consistency.
- ec = INVALID_STATE_ERR;
- }
-
- return 0;
-}
-
-String XMLHttpRequest::statusText(ExceptionCode& ec) const
-{
- // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=3547> XMLHttpRequest.statusText returns always "OK".
- if (m_response.httpStatusCode())
- return "OK";
-
- if (m_state == OPENED) {
- // See comments in getStatus() above.
- ec = INVALID_STATE_ERR;
- }
-
- return String();
-}
-
-void XMLHttpRequest::processSyncLoadResults(const Vector<char>& data, const ResourceResponse& response, ExceptionCode& ec)
-{
- if (m_sameOriginRequest && !m_doc->securityOrigin()->canRequest(response.url())) {
- abort();
- return;
- }
-
- didReceiveResponse(0, response);
- changeState(HEADERS_RECEIVED);
-
- const char* bytes = static_cast<const char*>(data.data());
- int len = static_cast<int>(data.size());
- didReceiveData(0, bytes, len);
-
- didFinishLoading(0);
- if (m_error)
- ec = XMLHttpRequestException::NETWORK_ERR;
-}
-
-void XMLHttpRequest::didFail(SubresourceLoader* loader, const ResourceError& error)
-{
- // If we are already in an error state, for instance we called abort(), bail out early.
- if (m_error)
- return;
-
- if (error.isCancellation()) {
- abortError();
- return;
- }
-
- networkError();
- return;
-}
-
-void XMLHttpRequest::didFinishLoading(SubresourceLoader* loader)
-{
- if (m_error)
- return;
-
- if (m_inPreflight) {
- didFinishLoadingPreflight(loader);
- return;
- }
-
- ASSERT(loader == m_loader);
-
- if (m_state < HEADERS_RECEIVED)
- changeState(HEADERS_RECEIVED);
-
- if (m_decoder)
- m_responseText += m_decoder->flush();
-
- if (Frame* frame = m_doc->frame()) {
- if (Page* page = frame->page()) {
- page->inspectorController()->resourceRetrievedByXMLHttpRequest(m_loader ? m_loader->identifier() : m_identifier, m_responseText);
- page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageLevel, "XHR finished loading \"" + m_url + "\".", 0, m_doc->url());
- }
- }
-
- bool hadLoader = m_loader;
- m_loader = 0;
-
- changeState(DONE);
- m_decoder = 0;
-
- if (hadLoader)
- dropProtection();
-}
-
-void XMLHttpRequest::didFinishLoadingPreflight(SubresourceLoader* loader)
-{
- ASSERT(m_inPreflight);
- ASSERT(!m_sameOriginRequest);
-
- // FIXME: this can probably be moved to didReceiveResponsePreflight.
- if (m_async)
- handleAsynchronousPreflightResult();
-}
-
-void XMLHttpRequest::willSendRequest(SubresourceLoader*, ResourceRequest& request, const ResourceResponse& redirectResponse)
-{
- // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
- if (!m_doc->securityOrigin()->canRequest(request.url())) {
- internalAbort();
- networkError();
- }
-}
-
-void XMLHttpRequest::didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
-{
- if (!m_upload)
- return;
-
- m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent);
-
- if (bytesSent == totalBytesToBeSent && !m_uploadComplete) {
- m_uploadComplete = true;
- m_upload->dispatchLoadEvent();
- }
-}
-
-bool XMLHttpRequest::accessControlCheck(const ResourceResponse& response)
-{
- const String& accessControlOriginString = response.httpHeaderField("Access-Control-Origin");
- if (accessControlOriginString == "*" && !m_includeCredentials)
- return true;
-
- KURL accessControlOriginURL(accessControlOriginString);
- if (!accessControlOriginURL.isValid())
- return false;
-
- RefPtr<SecurityOrigin> accessControlOrigin = SecurityOrigin::create(accessControlOriginURL);
- if (!accessControlOrigin->isSameSchemeHostPort(m_doc->securityOrigin()))
- return false;
-
- if (m_includeCredentials) {
- const String& accessControlCredentialsString = response.httpHeaderField("Access-Control-Credentials");
- if (accessControlCredentialsString != "true")
- return false;
- }
-
- return true;
-}
-
-void XMLHttpRequest::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response)
-{
- if (m_inPreflight) {
- didReceiveResponsePreflight(loader, response);
- return;
- }
-
- if (!m_sameOriginRequest) {
- if (!accessControlCheck(response)) {
- networkError();
- return;
- }
- }
-
- m_response = response;
- m_responseEncoding = extractCharsetFromMediaType(m_mimeTypeOverride);
- if (m_responseEncoding.isEmpty())
- m_responseEncoding = response.textEncodingName();
-}
-
-template<class HashType>
-static bool parseAccessControlAllowList(const String& string, HashSet<String, HashType>* set)
-{
- int start = 0;
- int end;
- while ((end = string.find(',', start)) != -1) {
- if (start == end)
- return false;
-
- // FIXME: this could be made more efficient by not not allocating twice.
- set->add(string.substring(start, end - start).stripWhiteSpace());
- start = end + 1;
- }
- if (start != static_cast<int>(string.length()))
- set->add(string.substring(start).stripWhiteSpace());
-
- return true;
-}
-
-static bool parseAccessControlMaxAge(const String& string, unsigned& expiryDelta)
-{
- // FIXME: this will not do the correct thing for a number starting with a '+'
- bool ok = false;
- expiryDelta = string.toUIntStrict(&ok);
- return ok;
-}
-
-void XMLHttpRequest::didReceiveResponsePreflight(SubresourceLoader*, const ResourceResponse& response)
-{
- ASSERT(m_inPreflight);
- ASSERT(!m_sameOriginRequest);
-
- if (!accessControlCheck(response)) {
- networkError();
- return;
- }
-
- OwnPtr<HashSet<String> > methods(new HashSet<String>);
- if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Methods"), methods.get())) {
- networkError();
- return;
- }
-
- if (!methods->contains(m_method) && m_method != "GET" && m_method != "POST") {
- networkError();
- return;
- }
-
- OwnPtr<HashSet<String, CaseFoldingHash> > headers(new HashSet<String, CaseFoldingHash>);
- if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Headers"), headers.get())) {
- networkError();
- return;
- }
-
- HTTPHeaderMap::const_iterator end = m_requestHeaders.end();
- for (HTTPHeaderMap::const_iterator it = m_requestHeaders.begin(); it != end; ++it) {
- if (!headers->contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first)) {
- networkError();
- return;
- }
- }
-
- unsigned expiryDelta = 0;
- if (!parseAccessControlMaxAge(response.httpHeaderField("Access-Control-Max-Age"), expiryDelta))
- expiryDelta = 5;
-
- appendPreflightResultCacheEntry(accessControlOrigin(), m_url, expiryDelta, m_includeCredentials, methods.release(), headers.release());
-}
-
-void XMLHttpRequest::receivedCancellation(SubresourceLoader*, const AuthenticationChallenge& challenge)
-{
- m_response = challenge.failureResponse();
-}
-
-void XMLHttpRequest::didReceiveData(SubresourceLoader*, const char* data, int len)
-{
- if (m_inPreflight)
- return;
-
- if (m_state < HEADERS_RECEIVED)
- changeState(HEADERS_RECEIVED);
-
- if (!m_decoder) {
- if (!m_responseEncoding.isEmpty())
- m_decoder = TextResourceDecoder::create("text/plain", m_responseEncoding);
- // allow TextResourceDecoder to look inside the m_response if it's XML or HTML
- else if (responseIsXML())
- m_decoder = TextResourceDecoder::create("application/xml");
- else if (responseMIMEType() == "text/html")
- m_decoder = TextResourceDecoder::create("text/html", "UTF-8");
- else
- m_decoder = TextResourceDecoder::create("text/plain", "UTF-8");
- }
- if (len == 0)
- return;
-
- if (len == -1)
- len = strlen(data);
-
- String decoded = m_decoder->decode(data, len);
-
- m_responseText += decoded;
-
- if (!m_error) {
- updateAndDispatchOnProgress(len);
-
- if (m_state != LOADING)
- changeState(LOADING);
- else
- // Firefox calls readyStateChanged every time it receives data, 4449442
- callReadyStateChangeListener();
- }
-}
-
-void XMLHttpRequest::updateAndDispatchOnProgress(unsigned int len)
-{
- long long expectedLength = m_response.expectedContentLength();
- m_receivedLength += len;
-
- // FIXME: the spec requires that we dispatch the event according to the least
- // frequent method between every 350ms (+/-200ms) and for every byte received.
- dispatchProgressEvent(expectedLength);
-}
-
-void XMLHttpRequest::dispatchReadyStateChangeEvent()
-{
- RefPtr<Event> evt = Event::create(readystatechangeEvent, false, false);
- if (m_onReadyStateChangeListener) {
- evt->setTarget(this);
- evt->setCurrentTarget(this);
- m_onReadyStateChangeListener->handleEvent(evt.get(), false);
- }
-
- ExceptionCode ec = 0;
- dispatchEvent(evt.release(), ec, false);
- ASSERT(!ec);
-}
-
-void XMLHttpRequest::dispatchXMLHttpRequestProgressEvent(EventListener* listener, const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total)
-{
- RefPtr<XMLHttpRequestProgressEvent> evt = XMLHttpRequestProgressEvent::create(type, lengthComputable, loaded, total);
- if (listener) {
- evt->setTarget(this);
- evt->setCurrentTarget(this);
- listener->handleEvent(evt.get(), false);
- }
-
- ExceptionCode ec = 0;
- dispatchEvent(evt.release(), ec, false);
- ASSERT(!ec);
-}
-
-void XMLHttpRequest::dispatchAbortEvent()
-{
- dispatchXMLHttpRequestProgressEvent(m_onAbortListener.get(), abortEvent, false, 0, 0);
-}
-
-void XMLHttpRequest::dispatchErrorEvent()
-{
- dispatchXMLHttpRequestProgressEvent(m_onErrorListener.get(), errorEvent, false, 0, 0);
-}
-
-void XMLHttpRequest::dispatchLoadEvent()
-{
- dispatchXMLHttpRequestProgressEvent(m_onLoadListener.get(), loadEvent, false, 0, 0);
-}
-
-void XMLHttpRequest::dispatchLoadStartEvent()
-{
- dispatchXMLHttpRequestProgressEvent(m_onLoadStartListener.get(), loadstartEvent, false, 0, 0);
-}
-
-void XMLHttpRequest::dispatchProgressEvent(long long expectedLength)
-{
- dispatchXMLHttpRequestProgressEvent(m_onProgressListener.get(), progressEvent, expectedLength && m_receivedLength <= expectedLength,
- static_cast<unsigned>(m_receivedLength), static_cast<unsigned>(expectedLength));
-}
-
-void XMLHttpRequest::cancelRequests(Document* m_doc)
-{
- RequestsSet* requests = requestsByDocument().get(m_doc);
- if (!requests)
- return;
- RequestsSet copy = *requests;
- RequestsSet::const_iterator end = copy.end();
- for (RequestsSet::const_iterator it = copy.begin(); it != end; ++it)
- (*it)->internalAbort();
-}
-
-void XMLHttpRequest::detachRequests(Document* m_doc)
-{
- RequestsSet* requests = requestsByDocument().get(m_doc);
- if (!requests)
- return;
- requestsByDocument().remove(m_doc);
- RequestsSet::const_iterator end = requests->end();
- for (RequestsSet::const_iterator it = requests->begin(); it != end; ++it) {
- (*it)->m_doc = 0;
- (*it)->internalAbort();
- }
- delete requests;
-}
-
-} // namespace WebCore
diff --git a/webkit/pending/XMLHttpRequest.h b/webkit/pending/XMLHttpRequest.h
deleted file mode 100644
index 77d32e6..0000000
--- a/webkit/pending/XMLHttpRequest.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2005, 2006 Alexey Proskuryakov <ap@nypop.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef XMLHttpRequest_h
-#define XMLHttpRequest_h
-
-#include "EventListener.h"
-#include "EventTarget.h"
-#include "FormData.h"
-#include "ResourceResponse.h"
-#include "SubresourceLoaderClient.h"
-#include "ScriptController.h"
-#include <wtf/OwnPtr.h>
-
-namespace WebCore {
-
-class Document;
-class File;
-class TextResourceDecoder;
-
-class XMLHttpRequest : public RefCounted<XMLHttpRequest>, public EventTarget, private SubresourceLoaderClient {
-public:
- static PassRefPtr<XMLHttpRequest> create(Document* document) { return adoptRef(new XMLHttpRequest(document)); }
- ~XMLHttpRequest();
-
- // These exact numeric values are important because JS expects them.
- enum State {
- UNSENT = 0,
- OPENED = 1,
- HEADERS_RECEIVED = 2,
- LOADING = 3,
- DONE = 4
- };
-
- virtual XMLHttpRequest* toXMLHttpRequest() { return this; }
-
- static void detachRequests(Document*);
- static void cancelRequests(Document*);
-
- String statusText(ExceptionCode&) const;
- int status(ExceptionCode&) const;
- State readyState() const;
- void open(const String& method, const KURL&, bool async, ExceptionCode&);
- void open(const String& method, const KURL&, bool async, const String& user, ExceptionCode&);
- void open(const String& method, const KURL&, bool async, const String& user, const String& password, ExceptionCode&);
- void send(ExceptionCode&);
- void send(Document*, ExceptionCode&);
- void send(const String&, ExceptionCode&);
- void send(File*, ExceptionCode&);
- void abort();
- void setRequestHeader(const String& name, const String& value, ExceptionCode&);
- void overrideMimeType(const String& override);
- String getAllResponseHeaders(ExceptionCode&) const;
- String getResponseHeader(const String& name, ExceptionCode&) const;
- const JSString& responseText() const;
- Document* responseXML() const;
-
- XMLHttpRequestUpload* upload();
- XMLHttpRequestUpload* optionalUpload() const { return m_upload.get(); }
-
- void setOnReadyStateChangeListener(PassRefPtr<EventListener> eventListener) { m_onReadyStateChangeListener = eventListener; }
- EventListener* onReadyStateChangeListener() const { return m_onReadyStateChangeListener.get(); }
-
- void setOnAbortListener(PassRefPtr<EventListener> eventListener) { m_onAbortListener = eventListener; }
- EventListener* onAbortListener() const { return m_onAbortListener.get(); }
-
- void setOnErrorListener(PassRefPtr<EventListener> eventListener) { m_onErrorListener = eventListener; }
- EventListener* onErrorListener() const { return m_onErrorListener.get(); }
-
- void setOnLoadListener(PassRefPtr<EventListener> eventListener) { m_onLoadListener = eventListener; }
- EventListener* onLoadListener() const { return m_onLoadListener.get(); }
-
- void setOnLoadStartListener(PassRefPtr<EventListener> eventListener) { m_onLoadStartListener = eventListener; }
- EventListener* onLoadStartListener() const { return m_onLoadStartListener.get(); }
-
- void setOnProgressListener(PassRefPtr<EventListener> eventListener) { m_onProgressListener = eventListener; }
- EventListener* onProgressListener() const { return m_onProgressListener.get(); }
-
-#if USE(V8)
- // Sam Weinig says that upstream WebKit plans to rename the above methods
- // to have these same names for the bindings as well.
- void setOnreadystatechange(EventListener* listener) { setOnReadyStateChangeListener(listener); }
- EventListener* onreadystatechange() const { return onReadyStateChangeListener(); }
-
- void setOnabort(PassRefPtr<EventListener> eventListener) { m_onAbortListener = eventListener; }
- EventListener* onabort() const { return m_onAbortListener.get(); }
-
- void setOnerror(PassRefPtr<EventListener> eventListener) { m_onErrorListener = eventListener; }
- EventListener* onerror() const { return m_onErrorListener.get(); }
-
- void setOnload(EventListener* listener) { setOnLoadListener(listener); }
- EventListener* onload() const { return onLoadListener(); }
-
- void setOnloadstart(PassRefPtr<EventListener> eventListener) { m_onLoadStartListener = eventListener; }
- EventListener* onloadstart() const { return m_onLoadStartListener.get(); }
-
- void setOnprogress(PassRefPtr<EventListener> eventListener) { m_onProgressListener = eventListener; }
- EventListener* onprogress() const { return m_onProgressListener.get(); }
-#endif
-
- typedef Vector<RefPtr<EventListener> > ListenerVector;
- typedef HashMap<AtomicStringImpl*, ListenerVector> EventListenersMap;
-
- // useCapture is not used, even for add/remove pairing (for Firefox compatibility).
- virtual void addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
- virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
- virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&, bool tempEvent = false);
- EventListenersMap& eventListeners() { return m_eventListeners; }
-
- Document* document() const { return m_doc; }
-
- using RefCounted<XMLHttpRequest>::ref;
- using RefCounted<XMLHttpRequest>::deref;
-
- Document* getOwnerDocument() { return m_doc; }
-
-private:
- XMLHttpRequest(Document*);
-
- virtual void refEventTarget() { ref(); }
- virtual void derefEventTarget() { deref(); }
-
- virtual void willSendRequest(SubresourceLoader*, ResourceRequest& request, const ResourceResponse& redirectResponse);
- virtual void didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
- virtual void didReceiveResponse(SubresourceLoader*, const ResourceResponse&);
- virtual void didReceiveData(SubresourceLoader*, const char* data, int size);
- virtual void didFail(SubresourceLoader*, const ResourceError&);
- virtual void didFinishLoading(SubresourceLoader*);
- virtual void receivedCancellation(SubresourceLoader*, const AuthenticationChallenge&);
-
- // Special versions for the preflight
- void didReceiveResponsePreflight(SubresourceLoader*, const ResourceResponse&);
- void didFinishLoadingPreflight(SubresourceLoader*);
-
- void processSyncLoadResults(const Vector<char>& data, const ResourceResponse&, ExceptionCode&);
- void updateAndDispatchOnProgress(unsigned int len);
-
- String responseMIMEType() const;
- bool responseIsXML() const;
-
- bool initSend(ExceptionCode&);
-
- String getRequestHeader(const String& name) const;
- void setRequestHeaderInternal(const String& name, const String& value);
-
- void changeState(State newState);
- void callReadyStateChangeListener();
- void dropProtection();
- void internalAbort();
- void clearResponse();
- void clearRequest();
-
- void createRequest(ExceptionCode&);
-
- void makeSameOriginRequest(ExceptionCode&);
- void makeCrossSiteAccessRequest(ExceptionCode&);
-
- void makeSimpleCrossSiteAccessRequest(ExceptionCode&);
- void makeCrossSiteAccessRequestWithPreflight(ExceptionCode&);
- void handleAsynchronousPreflightResult();
-
- void loadRequestSynchronously(ResourceRequest&, ExceptionCode&);
- void loadRequestAsynchronously(ResourceRequest&);
-
- bool isSimpleCrossSiteAccessRequest() const;
- String accessControlOrigin() const;
- bool accessControlCheck(const ResourceResponse&);
-
- void genericError();
- void networkError();
- void abortError();
-
- void dispatchReadyStateChangeEvent();
- void dispatchXMLHttpRequestProgressEvent(EventListener* listener, const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total);
- void dispatchAbortEvent();
- void dispatchErrorEvent();
- void dispatchLoadEvent();
- void dispatchLoadStartEvent();
- void dispatchProgressEvent(long long expectedLength);
-
- Document* m_doc;
-
- RefPtr<EventListener> m_onReadyStateChangeListener;
- RefPtr<EventListener> m_onAbortListener;
- RefPtr<EventListener> m_onErrorListener;
- RefPtr<EventListener> m_onLoadListener;
- RefPtr<EventListener> m_onLoadStartListener;
- RefPtr<EventListener> m_onProgressListener;
- EventListenersMap m_eventListeners;
-
- RefPtr<XMLHttpRequestUpload> m_upload;
-
- KURL m_url;
- String m_method;
- HTTPHeaderMap m_requestHeaders;
- RefPtr<FormData> m_requestEntityBody;
- String m_mimeTypeOverride;
- bool m_async;
- bool m_includeCredentials;
-
- RefPtr<SubresourceLoader> m_loader;
- State m_state;
-
- ResourceResponse m_response;
- String m_responseEncoding;
-
- RefPtr<TextResourceDecoder> m_decoder;
- unsigned long m_identifier;
-
- // Unlike most strings in the DOM, we keep this as a KJS::UString, not a WebCore::String.
- // That's because these strings can easily get huge (they are filled from the network with
- // no parsing) and because JS can easily observe many intermediate states, so it's very useful
- // to be able to share the buffer with JavaScript versions of the whole or partial string.
- // In contrast, this string doesn't interact much with the rest of the engine so it's not that
- // big a cost that it isn't a String.
- JSString m_responseText;
- mutable bool m_createdDocument;
- mutable RefPtr<Document> m_responseXML;
-
- bool m_error;
-
- bool m_uploadComplete;
-
- bool m_sameOriginRequest;
- bool m_allowAccess;
- bool m_inPreflight;
-
- // Used for onprogress tracking
- long long m_receivedLength;
-};
-
-} // namespace WebCore
-
-#endif // XMLHttpRequest_h
diff --git a/webkit/pending/XSLImportRule.cpp b/webkit/pending/XSLImportRule.cpp
deleted file mode 100644
index 6ceb108..0000000
--- a/webkit/pending/XSLImportRule.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * This file is part of the XSL implementation.
- *
- * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "XSLImportRule.h"
-
-#if ENABLE(XSLT)
-
-#include "CachedXSLStyleSheet.h"
-#include "DocLoader.h"
-#include "XSLStyleSheet.h"
-
-namespace WebCore {
-
-XSLImportRule::XSLImportRule(XSLStyleSheet* parent, const String& href)
- : StyleBase(parent)
- , m_strHref(href)
- , m_cachedSheet(0)
- , m_loading(false)
-{
-}
-
-XSLImportRule::~XSLImportRule()
-{
- if (m_styleSheet)
- m_styleSheet->setParent(0);
-
- if (m_cachedSheet)
- m_cachedSheet->removeClient(this);
-}
-
-XSLStyleSheet* XSLImportRule::parentStyleSheet() const
-{
- return (parent() && parent()->isXSLStyleSheet()) ? static_cast<XSLStyleSheet*>(parent()) : 0;
-}
-
-void XSLImportRule::setXSLStyleSheet(const String& url, const String& sheet)
-{
- if (m_styleSheet)
- m_styleSheet->setParent(0);
-
- m_styleSheet = XSLStyleSheet::create(this, url);
-
- XSLStyleSheet* parent = parentStyleSheet();
- if (parent)
- m_styleSheet->setParentStyleSheet(parent);
-
- m_styleSheet->parseString(sheet);
- m_loading = false;
-
- if (parent)
- parent->checkLoaded();
-}
-
-bool XSLImportRule::isLoading()
-{
- return (m_loading || (m_styleSheet && m_styleSheet->isLoading()));
-}
-
-void XSLImportRule::loadSheet()
-{
- DocLoader* docLoader = 0;
- StyleBase* root = this;
- StyleBase* parent;
- while ((parent = root->parent()))
- root = parent;
- if (root->isXSLStyleSheet())
- docLoader = static_cast<XSLStyleSheet*>(root)->docLoader();
-
- String absHref = m_strHref;
- XSLStyleSheet* parentSheet = parentStyleSheet();
- if (!parentSheet->href().isNull())
- // use parent styleheet's URL as the base URL
- absHref = KURL(KURL(parentSheet->href()), m_strHref).string();
-
- // Check for a cycle in our import chain. If we encounter a stylesheet
- // in our parent chain with the same URL, then just bail.
- for (parent = this->parent(); parent; parent = parent->parent()) {
- if (parent->isXSLStyleSheet() && absHref == static_cast<XSLStyleSheet*>(parent)->href())
- return;
- }
-
- m_cachedSheet = docLoader->requestXSLStyleSheet(absHref);
-
- if (m_cachedSheet) {
- m_cachedSheet->addClient(this);
-
- // If the imported sheet is in the cache, then setXSLStyleSheet gets called,
- // and the sheet even gets parsed (via parseString). In this case we have
- // loaded (even if our subresources haven't), so if we have a stylesheet after
- // checking the cache, then we've clearly loaded.
- if (!m_styleSheet)
- m_loading = true;
- }
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(XSLT)
diff --git a/webkit/pending/XSLStyleSheet.cpp b/webkit/pending/XSLStyleSheet.cpp
deleted file mode 100644
index 316db15..0000000
--- a/webkit/pending/XSLStyleSheet.cpp
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * This file is part of the XSL implementation.
- *
- * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "config.h"
-#include "XSLStyleSheet.h"
-
-#if ENABLE(XSLT)
-
-#include "CString.h"
-#include "Console.h"
-#include "DOMWindow.h"
-#include "DocLoader.h"
-#include "Document.h"
-#include "Frame.h"
-#include "loader.h"
-#include "Node.h"
-#include "XMLTokenizer.h"
-#include "XSLImportRule.h"
-#include "XSLTProcessor.h"
-
-#include <libxml/uri.h>
-#include <libxslt/xsltutils.h>
-
-#if PLATFORM(MAC)
-#include "SoftLinking.h"
-#endif
-
-#if PLATFORM(MAC)
-SOFT_LINK_LIBRARY(libxslt)
-SOFT_LINK(libxslt, xsltIsBlank, int, (xmlChar *str), (str))
-SOFT_LINK(libxslt, xsltGetNsProp, xmlChar *, (xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace), (node, name, nameSpace))
-SOFT_LINK(libxslt, xsltParseStylesheetDoc, xsltStylesheetPtr, (xmlDocPtr doc), (doc))
-SOFT_LINK(libxslt, xsltLoadStylesheetPI, xsltStylesheetPtr, (xmlDocPtr doc), (doc))
-#endif
-
-namespace WebCore {
-
-XSLStyleSheet::XSLStyleSheet(XSLImportRule* parentRule, const String& href)
- : StyleSheet(parentRule, href)
- , m_ownerDocument(0)
- , m_stylesheetDoc(0)
- , m_embedded(false)
- , m_processed(false) // Child sheets get marked as processed when the libxslt engine has finally seen them.
- , m_stylesheetDocTaken(false)
- , m_parentStyleSheet(0)
-{
-}
-
-XSLStyleSheet::XSLStyleSheet(Node* parentNode, const String& href, bool embedded)
- : StyleSheet(parentNode, href)
- , m_ownerDocument(parentNode->document())
- , m_stylesheetDoc(0)
- , m_embedded(embedded)
- , m_processed(true) // The root sheet starts off processed.
- , m_stylesheetDocTaken(false)
- , m_parentStyleSheet(0)
-{
-}
-
-XSLStyleSheet::~XSLStyleSheet()
-{
- if (!m_stylesheetDocTaken)
- xmlFreeDoc(m_stylesheetDoc);
-}
-
-bool XSLStyleSheet::isLoading()
-{
- unsigned len = length();
- for (unsigned i = 0; i < len; ++i) {
- StyleBase* rule = item(i);
- if (rule->isImportRule()) {
- XSLImportRule* import = static_cast<XSLImportRule*>(rule);
- if (import->isLoading())
- return true;
- }
- }
- return false;
-}
-
-void XSLStyleSheet::checkLoaded()
-{
- if (isLoading())
- return;
- if (parent())
- parent()->checkLoaded();
- if (ownerNode())
- ownerNode()->sheetLoaded();
-}
-
-xmlDocPtr XSLStyleSheet::document()
-{
- if (m_embedded && ownerDocument())
- return (xmlDocPtr)ownerDocument()->transformSource();
- return m_stylesheetDoc;
-}
-
-void XSLStyleSheet::clearDocuments()
-{
- m_stylesheetDoc = 0;
- unsigned len = length();
- for (unsigned i = 0; i < len; ++i) {
- StyleBase* rule = item(i);
- if (rule->isImportRule()) {
- XSLImportRule* import = static_cast<XSLImportRule*>(rule);
- if (import->styleSheet())
- import->styleSheet()->clearDocuments();
- }
- }
-}
-
-DocLoader* XSLStyleSheet::docLoader()
-{
- if (!m_ownerDocument)
- return 0;
- return m_ownerDocument->docLoader();
-}
-
-bool XSLStyleSheet::parseString(const String& string, bool strict)
-{
- // Parse in a single chunk into an xmlDocPtr
- const UChar BOM = 0xFEFF;
- const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
- setLoaderForLibXMLCallbacks(docLoader());
- if (!m_stylesheetDocTaken)
- xmlFreeDoc(m_stylesheetDoc);
- m_stylesheetDocTaken = false;
-
- Console* console = 0;
- if (Frame* frame = ownerDocument()->frame())
- console = frame->domWindow()->console();
- xmlSetStructuredErrorFunc(console, XSLTProcessor::parseErrorFunc);
- xmlSetGenericErrorFunc(console, XSLTProcessor::genericErrorFunc);
-
- xmlParserCtxtPtr ctxt =
- xmlCreateMemoryParserCtxt(reinterpret_cast<const char*>(string.characters()), string.length());
-
- if (parentStyleSheet())
- {
- // Child stylesheets should use the same libxml dictionary as
- // their parents. Otherwise both dictionaries end up trying to
- // free the same memory.
- xmlDictFree(ctxt->dict);
- ctxt->dict = parentStyleSheet()->m_stylesheetDoc->dict;
- }
-
- m_stylesheetDoc = xmlCtxtReadMemory(ctxt, reinterpret_cast<const char*>(string.characters()), string.length() * sizeof(UChar),
- href().utf8().data(),
- BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE",
- XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_NOWARNING | XML_PARSE_NOCDATA);
- // If we had already freed the dict memory, do not try to clean it up
- // again.
- if (parentStyleSheet())
- ctxt->dict = NULL;
- xmlFreeParserCtxt(ctxt);
-
- loadChildSheets();
-
- xmlSetStructuredErrorFunc(0, 0);
- xmlSetGenericErrorFunc(0, 0);
-
- setLoaderForLibXMLCallbacks(0);
- return m_stylesheetDoc;
-}
-
-void XSLStyleSheet::loadChildSheets()
-{
- if (!document())
- return;
-
- xmlNodePtr stylesheetRoot = document()->children;
-
- // Top level children may include other things such as DTD nodes, we ignore those.
- while (stylesheetRoot && stylesheetRoot->type != XML_ELEMENT_NODE)
- stylesheetRoot = stylesheetRoot->next;
-
- if (m_embedded) {
- // We have to locate (by ID) the appropriate embedded stylesheet element, so that we can walk the
- // import/include list.
- xmlAttrPtr idNode = xmlGetID(document(), (const xmlChar*)(href().utf8().data()));
- if (!idNode)
- return;
- stylesheetRoot = idNode->parent;
- } else {
- // FIXME: Need to handle an external URI with a # in it. This is a pretty minor edge case, so we'll deal
- // with it later.
- }
-
- if (stylesheetRoot) {
- // Walk the children of the root element and look for import/include elements.
- // Imports must occur first.
- xmlNodePtr curr = stylesheetRoot->children;
- while (curr) {
- if (curr->type != XML_ELEMENT_NODE) {
- curr = curr->next;
- continue;
- }
- if (IS_XSLT_ELEM(curr) && IS_XSLT_NAME(curr, "import")) {
- xmlChar* uriRef = xsltGetNsProp(curr, (const xmlChar*)"href", XSLT_NAMESPACE);
- loadChildSheet(String::fromUTF8((const char*)uriRef));
- xmlFree(uriRef);
- } else
- break;
- curr = curr->next;
- }
-
- // Now handle includes.
- while (curr) {
- if (curr->type == XML_ELEMENT_NODE && IS_XSLT_ELEM(curr) && IS_XSLT_NAME(curr, "include")) {
- xmlChar* uriRef = xsltGetNsProp(curr, (const xmlChar*)"href", XSLT_NAMESPACE);
- loadChildSheet(String::fromUTF8((const char*)uriRef));
- xmlFree(uriRef);
- }
- curr = curr->next;
- }
- }
-}
-
-void XSLStyleSheet::loadChildSheet(const String& href)
-{
- RefPtr<XSLImportRule> childRule = XSLImportRule::create(this, href);
- append(childRule);
- childRule->loadSheet();
-}
-
-xsltStylesheetPtr XSLStyleSheet::compileStyleSheet()
-{
- // FIXME: Hook up error reporting for the stylesheet compilation process.
- if (m_embedded)
- return xsltLoadStylesheetPI(document());
-
- // xsltParseStylesheetDoc makes the document part of the stylesheet
- // so we have to release our pointer to it.
- ASSERT(!m_stylesheetDocTaken);
- xsltStylesheetPtr result = xsltParseStylesheetDoc(m_stylesheetDoc);
- if (result)
- m_stylesheetDocTaken = true;
- return result;
-}
-
-xmlDocPtr XSLStyleSheet::locateStylesheetSubResource(xmlDocPtr parentDoc, const xmlChar* uri)
-{
- bool matchedParent = (parentDoc == document());
- unsigned len = length();
- for (unsigned i = 0; i < len; ++i) {
- StyleBase* rule = item(i);
- if (rule->isImportRule()) {
- XSLImportRule* import = static_cast<XSLImportRule*>(rule);
- XSLStyleSheet* child = import->styleSheet();
- if (!child)
- continue;
- if (matchedParent) {
- if (child->processed())
- continue; // libxslt has been given this sheet already.
-
- // Check the URI of the child stylesheet against the doc URI.
- // In order to ensure that libxml canonicalized both URLs, we get the original href
- // string from the import rule and canonicalize it using libxml before comparing it
- // with the URI argument.
- CString importHref = import->href().utf8();
- xmlChar* base = xmlNodeGetBase(parentDoc, (xmlNodePtr)parentDoc);
- xmlChar* childURI = xmlBuildURI((const xmlChar*)importHref.data(), base);
- bool equalURIs = xmlStrEqual(uri, childURI);
- xmlFree(base);
- xmlFree(childURI);
- if (equalURIs) {
- child->markAsProcessed();
- return child->document();
- }
- } else {
- xmlDocPtr result = import->styleSheet()->locateStylesheetSubResource(parentDoc, uri);
- if (result)
- return result;
- }
- }
- }
-
- return 0;
-}
-
-void XSLStyleSheet::markAsProcessed()
-{
- ASSERT(!m_processed);
- ASSERT(!m_stylesheetDocTaken);
- m_processed = true;
- m_stylesheetDocTaken = true;
-}
-
-void XSLStyleSheet::setParentStyleSheet(XSLStyleSheet* parent)
-{
- m_parentStyleSheet = parent;
- if (parent) {
- setOwnerDocument(parent->ownerDocument());
- }
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(XSLT)
diff --git a/webkit/pending/XSLStyleSheet.h b/webkit/pending/XSLStyleSheet.h
deleted file mode 100644
index c6ed097..0000000
--- a/webkit/pending/XSLStyleSheet.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * This file is part of the XSL implementation.
- *
- * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef XSLStyleSheet_h
-#define XSLStyleSheet_h
-
-#if ENABLE(XSLT)
-
-#include "StyleSheet.h"
-#include <libxml/parser.h>
-#include <libxslt/transform.h>
-#include <wtf/PassRefPtr.h>
-
-namespace WebCore {
-
-class DocLoader;
-class Document;
-class XSLImportRule;
-
-class XSLStyleSheet : public StyleSheet {
-public:
- static PassRefPtr<XSLStyleSheet> create(XSLImportRule* parentImport, const String& href)
- {
- return adoptRef(new XSLStyleSheet(parentImport, href));
- }
- static PassRefPtr<XSLStyleSheet> create(Node* parentNode, const String& href)
- {
- return adoptRef(new XSLStyleSheet(parentNode, href, false));
- }
- static PassRefPtr<XSLStyleSheet> createEmbedded(Node* parentNode, const String& href)
- {
- return adoptRef(new XSLStyleSheet(parentNode, href, true));
- }
-
- virtual ~XSLStyleSheet();
-
- virtual bool isXSLStyleSheet() const { return true; }
-
- virtual String type() const { return "text/xml"; }
-
- virtual bool parseString(const String &string, bool strict = true);
-
- virtual bool isLoading();
- virtual void checkLoaded();
-
- void loadChildSheets();
- void loadChildSheet(const String& href);
-
- xsltStylesheetPtr compileStyleSheet();
-
- DocLoader* docLoader();
-
- Document* ownerDocument() { return m_ownerDocument; }
- void setOwnerDocument(Document* doc) { m_ownerDocument = doc; }
-
- xmlDocPtr document();
-
- void clearDocuments();
-
- xmlDocPtr locateStylesheetSubResource(xmlDocPtr parentDoc, const xmlChar* uri);
-
- void markAsProcessed();
- bool processed() const { return m_processed; }
-
- XSLStyleSheet* parentStyleSheet() { return m_parentStyleSheet; }
- void setParentStyleSheet(XSLStyleSheet* parent);
-
-private:
- XSLStyleSheet(Node* parentNode, const String& href, bool embedded);
- XSLStyleSheet(XSLImportRule* parentImport, const String& href);
-
- Document* m_ownerDocument;
- xmlDocPtr m_stylesheetDoc;
- bool m_embedded;
- bool m_processed;
- bool m_stylesheetDocTaken;
-
- XSLStyleSheet* m_parentStyleSheet;
-};
-
-} // namespace WebCore
-
-#endif // ENABLE(XSLT)
-
-#endif // XSLStyleSheet_h
diff --git a/webkit/pending/pcre_exec.cpp b/webkit/pending/pcre_exec.cpp
deleted file mode 100644
index c1f6fb8..0000000
--- a/webkit/pending/pcre_exec.cpp
+++ /dev/null
@@ -1,2176 +0,0 @@
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
- Copyright (C) 2007 Eric Seidel <eric@webkit.org>
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* This module contains jsRegExpExecute(), the externally visible function
-that does pattern matching using an NFA algorithm, following the rules from
-the JavaScript specification. There are also some supporting functions. */
-
-#include "config.h"
-#include "pcre_internal.h"
-
-#include <limits.h>
-#include <wtf/ASCIICType.h>
-#include <wtf/Vector.h>
-
-#if REGEXP_HISTOGRAM
-#include <kjs/DateMath.h>
-#include <kjs/ustring.h>
-#endif
-
-using namespace WTF;
-
-#ifdef __GNUC__
-#define USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-//#define USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-#endif
-
-/* Avoid warnings on Windows. */
-#undef min
-#undef max
-
-#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-typedef int ReturnLocation;
-#else
-typedef void* ReturnLocation;
-#endif
-
-#if !REGEXP_HISTOGRAM
-
-class HistogramTimeLogger {
-public:
- HistogramTimeLogger(const JSRegExp*) { }
-};
-
-#else
-
-using namespace KJS;
-
-class Histogram {
-public:
- ~Histogram();
- void add(const JSRegExp*, double);
-
-private:
- typedef HashMap<RefPtr<UString::Rep>, double> Map;
- Map times;
-};
-
-class HistogramTimeLogger {
-public:
- HistogramTimeLogger(const JSRegExp*);
- ~HistogramTimeLogger();
-
-private:
- const JSRegExp* m_re;
- double m_startTime;
-};
-
-#endif
-
-/* Structure for building a chain of data for holding the values of
-the subject pointer at the start of each bracket, used to detect when
-an empty string has been matched by a bracket to break infinite loops. */
-struct BracketChainNode {
- BracketChainNode* previousBracket;
- const UChar* bracketStart;
-};
-
-struct MatchFrame {
- ReturnLocation returnLocation;
- struct MatchFrame* previousFrame;
-
- /* Function arguments that may change */
- struct {
- const UChar* subjectPtr;
- const unsigned char* instructionPtr;
- int offsetTop;
- BracketChainNode* bracketChain;
- } args;
-
-
- /* PCRE uses "fake" recursion built off of gotos, thus
- stack-based local variables are not safe to use. Instead we have to
- store local variables on the current MatchFrame. */
- struct {
- const unsigned char* data;
- const unsigned char* startOfRepeatingBracket;
- const UChar* subjectPtrAtStartOfInstruction; // Several instrutions stash away a subjectPtr here for later compare
- const unsigned char* instructionPtrAtStartOfOnce;
-
- int repeatOthercase;
-
- int ctype;
- int fc;
- int fi;
- int length;
- int max;
- int number;
- int offset;
- int saveOffset1;
- int saveOffset2;
- int saveOffset3;
-
- BracketChainNode bracketChainNode;
- } locals;
-};
-
-/* Structure for passing "static" information around between the functions
-doing traditional NFA matching, so that they are thread-safe. */
-
-struct MatchData {
- int* offsetVector; /* Offset vector */
- int offsetEnd; /* One past the end */
- int offsetMax; /* The maximum usable for return data */
- bool offsetOverflow; /* Set if too many extractions */
- const UChar* startSubject; /* Start of the subject string */
- const UChar* endSubject; /* End of the subject string */
- const UChar* endMatchPtr; /* Subject position at end match */
- int endOffsetTop; /* Highwater mark at end of match */
- bool multiline;
- bool ignoreCase;
-};
-
-/* The maximum remaining length of subject we are prepared to search for a
-reqByte match. */
-
-#define REQ_BYTE_MAX 1000
-
-/* The below limit restricts the number of "recursive" match calls in order to
-avoid spending exponential time on complex regular expressions. */
-
-static const unsigned matchLimit = 100000;
-
-#ifdef DEBUG
-/*************************************************
-* Debugging function to print chars *
-*************************************************/
-
-/* Print a sequence of chars in printable format, stopping at the end of the
-subject if the requested.
-
-Arguments:
- p points to characters
- length number to print
- isSubject true if printing from within md.startSubject
- md pointer to matching data block, if isSubject is true
-*/
-
-static void pchars(const UChar* p, int length, bool isSubject, const MatchData& md)
-{
- if (isSubject && length > md.endSubject - p)
- length = md.endSubject - p;
- while (length-- > 0) {
- int c;
- if (isprint(c = *(p++)))
- printf("%c", c);
- else if (c < 256)
- printf("\\x%02x", c);
- else
- printf("\\x{%x}", c);
- }
-}
-#endif
-
-/*************************************************
-* Match a back-reference *
-*************************************************/
-
-/* If a back reference hasn't been set, the length that is passed is greater
-than the number of characters left in the string, so the match fails.
-
-Arguments:
- offset index into the offset vector
- subjectPtr points into the subject
- length length to be matched
- md points to match data block
-
-Returns: true if matched
-*/
-
-static bool matchRef(int offset, const UChar* subjectPtr, int length, const MatchData& md)
-{
- const UChar* p = md.startSubject + md.offsetVector[offset];
-
-#ifdef DEBUG
- if (subjectPtr >= md.endSubject)
- printf("matching subject <null>");
- else {
- printf("matching subject ");
- pchars(subjectPtr, length, true, md);
- }
- printf(" against backref ");
- pchars(p, length, false, md);
- printf("\n");
-#endif
-
- /* Always fail if not enough characters left */
-
- if (length > md.endSubject - subjectPtr)
- return false;
-
- /* Separate the caselesss case for speed */
-
- if (md.ignoreCase) {
- while (length-- > 0) {
- UChar c = *p++;
- int othercase = kjs_pcre_ucp_othercase(c);
- UChar d = *subjectPtr++;
- if (c != d && othercase != d)
- return false;
- }
- }
- else {
- while (length-- > 0)
- if (*p++ != *subjectPtr++)
- return false;
- }
-
- return true;
-}
-
-#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-
-/* Use numbered labels and switch statement at the bottom of the match function. */
-
-#define RMATCH_WHERE(num) num
-#define RRETURN_LABEL RRETURN_SWITCH
-
-#else
-
-/* Use GCC's computed goto extension. */
-
-/* For one test case this is more than 40% faster than the switch statement.
-We could avoid the use of the num argument entirely by using local labels,
-but using it for the GCC case as well as the non-GCC case allows us to share
-a bit more code and notice if we use conflicting numbers.*/
-
-#define RMATCH_WHERE(num) &&RRETURN_##num
-#define RRETURN_LABEL *stack.currentFrame->returnLocation
-
-#endif
-
-#define RECURSIVE_MATCH_COMMON(num) \
- goto RECURSE;\
- RRETURN_##num: \
- stack.popCurrentFrame();
-
-#define RECURSIVE_MATCH(num, ra, rb) \
- do { \
- stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \
- RECURSIVE_MATCH_COMMON(num) \
- } while (0)
-
-#define RECURSIVE_MATCH_NEW_GROUP(num, ra, rb) \
- do { \
- stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \
- startNewGroup(stack.currentFrame); \
- RECURSIVE_MATCH_COMMON(num) \
- } while (0)
-
-#define RRETURN goto RRETURN_LABEL
-
-#define RRETURN_NO_MATCH do { isMatch = false; RRETURN; } while (0)
-
-/*************************************************
-* Match from current position *
-*************************************************/
-
-/* On entry instructionPtr points to the first opcode, and subjectPtr to the first character
-in the subject string, while substringStart holds the value of subjectPtr at the start of the
-last bracketed group - used for breaking infinite loops matching zero-length
-strings. This function is called recursively in many circumstances. Whenever it
-returns a negative (error) response, the outer match() call must also return the
-same response.
-
-Arguments:
- subjectPtr pointer in subject
- instructionPtr position in code
- offsetTop current top pointer
- md pointer to "static" info for the match
-
-Returns: 1 if matched ) these values are >= 0
- 0 if failed to match )
- a negative error value if aborted by an error condition
- (e.g. stopped by repeated call or recursion limit)
-*/
-
-static const unsigned numFramesOnStack = 16;
-
-struct MatchStack {
- MatchStack()
- : framesEnd(frames + numFramesOnStack)
- , currentFrame(frames)
- , size(1) // match() creates accesses the first frame w/o calling pushNewFrame
- {
- ASSERT((sizeof(frames) / sizeof(frames[0])) == numFramesOnStack);
- }
-
- MatchFrame frames[numFramesOnStack];
- MatchFrame* framesEnd;
- MatchFrame* currentFrame;
- unsigned size;
-
- inline bool canUseStackBufferForNextFrame()
- {
- return size < numFramesOnStack;
- }
-
- inline MatchFrame* allocateNextFrame()
- {
- if (canUseStackBufferForNextFrame())
- return currentFrame + 1;
- return new MatchFrame;
- }
-
- inline void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation)
- {
- MatchFrame* newframe = allocateNextFrame();
- newframe->previousFrame = currentFrame;
-
- newframe->args.subjectPtr = currentFrame->args.subjectPtr;
- newframe->args.offsetTop = currentFrame->args.offsetTop;
- newframe->args.instructionPtr = instructionPtr;
- newframe->args.bracketChain = bracketChain;
- newframe->returnLocation = returnLocation;
- size++;
-
- currentFrame = newframe;
- }
-
- inline void popCurrentFrame()
- {
- MatchFrame* oldFrame = currentFrame;
- currentFrame = currentFrame->previousFrame;
- if (size > numFramesOnStack)
- delete oldFrame;
- size--;
- }
-
- void popAllFrames()
- {
- while (size)
- popCurrentFrame();
- }
-};
-
-static int matchError(int errorCode, MatchStack& stack)
-{
- stack.popAllFrames();
- return errorCode;
-}
-
-/* Get the next UTF-8 character, not advancing the pointer, incrementing length
- if there are extra bytes. This is called when we know we are in UTF-8 mode. */
-
-static inline void getUTF8CharAndIncrementLength(int& c, const unsigned char* subjectPtr, int& len)
-{
- c = *subjectPtr;
- if ((c & 0xc0) == 0xc0) {
- int gcaa = kjs_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */
- int gcss = 6 * gcaa;
- c = (c & kjs_pcre_utf8_table3[gcaa]) << gcss;
- for (int gcii = 1; gcii <= gcaa; gcii++) {
- gcss -= 6;
- c |= (subjectPtr[gcii] & 0x3f) << gcss;
- }
- len += gcaa;
- }
-}
-
-static inline void startNewGroup(MatchFrame* currentFrame)
-{
- /* At the start of a bracketed group, add the current subject pointer to the
- stack of such pointers, to be re-instated at the end of the group when we hit
- the closing ket. When match() is called in other circumstances, we don't add to
- this stack. */
-
- currentFrame->locals.bracketChainNode.previousBracket = currentFrame->args.bracketChain;
- currentFrame->locals.bracketChainNode.bracketStart = currentFrame->args.subjectPtr;
- currentFrame->args.bracketChain = &currentFrame->locals.bracketChainNode;
-}
-
-// FIXME: "minimize" means "not greedy", we should invert the callers to ask for "greedy" to be less confusing
-static inline void repeatInformationFromInstructionOffset(short instructionOffset, bool& minimize, int& minimumRepeats, int& maximumRepeats)
-{
- // Instruction offsets are based off of OP_CRSTAR, OP_STAR, OP_TYPESTAR, OP_NOTSTAR
- static const char minimumRepeatsFromInstructionOffset[] = { 0, 0, 1, 1, 0, 0 };
- static const int maximumRepeatsFromInstructionOffset[] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX, 1, 1 };
-
- ASSERT(instructionOffset >= 0);
- ASSERT(instructionOffset <= (OP_CRMINQUERY - OP_CRSTAR));
-
- minimize = (instructionOffset & 1); // this assumes ordering: Instruction, MinimizeInstruction, Instruction2, MinimizeInstruction2
- minimumRepeats = minimumRepeatsFromInstructionOffset[instructionOffset];
- maximumRepeats = maximumRepeatsFromInstructionOffset[instructionOffset];
-}
-
-static int match(const UChar* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData& md)
-{
- bool isMatch = false;
- int min;
- bool minimize = false; /* Initialization not really needed, but some compilers think so. */
- unsigned remainingMatchCount = matchLimit;
-
- MatchStack stack;
-
- /* The opcode jump table. */
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-#define EMIT_JUMP_TABLE_ENTRY(opcode) &&LABEL_OP_##opcode,
- static void* opcodeJumpTable[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) };
-#undef EMIT_JUMP_TABLE_ENTRY
-#endif
-
- /* One-time setup of the opcode jump table. */
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
- for (int i = 255; !opcodeJumpTable[i]; i--)
- opcodeJumpTable[i] = &&CAPTURING_BRACKET;
-#endif
-
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
- // Shark shows this as a hot line
- // Using a static const here makes this line disappear, but makes later access hotter (not sure why)
- stack.currentFrame->returnLocation = &&RETURN;
-#else
- stack.currentFrame->returnLocation = 0;
-#endif
- stack.currentFrame->args.subjectPtr = subjectPtr;
- stack.currentFrame->args.instructionPtr = instructionPtr;
- stack.currentFrame->args.offsetTop = offsetTop;
- stack.currentFrame->args.bracketChain = 0;
- startNewGroup(stack.currentFrame);
-
- /* This is where control jumps back to to effect "recursion" */
-
-RECURSE:
- if (!--remainingMatchCount)
- return matchError(JSRegExpErrorHitLimit, stack);
-
- /* Now start processing the operations. */
-
-#ifndef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
- while (true)
-#endif
- {
-
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-#define BEGIN_OPCODE(opcode) LABEL_OP_##opcode
-#define NEXT_OPCODE goto *opcodeJumpTable[*stack.currentFrame->args.instructionPtr]
-#else
-#define BEGIN_OPCODE(opcode) case OP_##opcode
-#define NEXT_OPCODE continue
-#endif
-
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
- NEXT_OPCODE;
-#else
- switch (*stack.currentFrame->args.instructionPtr)
-#endif
- {
- /* Non-capturing bracket: optimized */
-
- BEGIN_OPCODE(BRA):
- NON_CAPTURING_BRACKET:
- DPRINTF(("start bracket 0\n"));
- do {
- RECURSIVE_MATCH_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
- DPRINTF(("bracket 0 failed\n"));
- RRETURN;
-
- /* Skip over large extraction number data if encountered. */
-
- BEGIN_OPCODE(BRANUMBER):
- stack.currentFrame->args.instructionPtr += 3;
- NEXT_OPCODE;
-
- /* End of the pattern. */
-
- BEGIN_OPCODE(END):
- md.endMatchPtr = stack.currentFrame->args.subjectPtr; /* Record where we ended */
- md.endOffsetTop = stack.currentFrame->args.offsetTop; /* and how many extracts were taken */
- isMatch = true;
- RRETURN;
-
- /* Assertion brackets. Check the alternative branches in turn - the
- matching won't pass the KET for an assertion. If any one branch matches,
- the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
- start of each branch to move the current point backwards, so the code at
- this level is identical to the lookahead case. */
-
- BEGIN_OPCODE(ASSERT):
- do {
- RECURSIVE_MATCH_NEW_GROUP(6, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, NULL);
- if (isMatch)
- break;
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
- if (*stack.currentFrame->args.instructionPtr == OP_KET)
- RRETURN_NO_MATCH;
-
- /* Continue from after the assertion, updating the offsets high water
- mark, since extracts may have been taken during the assertion. */
-
- advanceToEndOfBracket(stack.currentFrame->args.instructionPtr);
- stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE;
- stack.currentFrame->args.offsetTop = md.endOffsetTop;
- NEXT_OPCODE;
-
- /* Negative assertion: all branches must fail to match */
-
- BEGIN_OPCODE(ASSERT_NOT):
- do {
- RECURSIVE_MATCH_NEW_GROUP(7, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, NULL);
- if (isMatch)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
-
- stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE;
- NEXT_OPCODE;
-
- /* An alternation is the end of a branch; scan along to find the end of the
- bracketed group and go to there. */
-
- BEGIN_OPCODE(ALT):
- advanceToEndOfBracket(stack.currentFrame->args.instructionPtr);
- NEXT_OPCODE;
-
- /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating
- that it may occur zero times. It may repeat infinitely, or not at all -
- i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
- repeat limits are compiled as a number of copies, with the optional ones
- preceded by BRAZERO or BRAMINZERO. */
-
- BEGIN_OPCODE(BRAZERO): {
- stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1;
- RECURSIVE_MATCH_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket);
- stack.currentFrame->args.instructionPtr = stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE;
- NEXT_OPCODE;
- }
-
- BEGIN_OPCODE(BRAMINZERO): {
- stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1;
- advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket);
- RECURSIVE_MATCH_NEW_GROUP(15, stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
- }
-
- /* End of a group, repeated or non-repeating. If we are at the end of
- an assertion "group", stop matching and return 1, but record the
- current high water mark for use by positive assertions. Do this also
- for the "once" (not-backup up) groups. */
-
- BEGIN_OPCODE(KET):
- BEGIN_OPCODE(KETRMIN):
- BEGIN_OPCODE(KETRMAX):
- stack.currentFrame->locals.instructionPtrAtStartOfOnce = stack.currentFrame->args.instructionPtr - getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.bracketChain->bracketStart;
-
- /* Back up the stack of bracket start pointers. */
-
- stack.currentFrame->args.bracketChain = stack.currentFrame->args.bracketChain->previousBracket;
-
- if (*stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT || *stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT_NOT) {
- md.endOffsetTop = stack.currentFrame->args.offsetTop;
- isMatch = true;
- RRETURN;
- }
-
- /* In all other cases except a conditional group we have to check the
- group number back at the start and if necessary complete handling an
- extraction by setting the offsets and bumping the high water mark. */
-
- stack.currentFrame->locals.number = *stack.currentFrame->locals.instructionPtrAtStartOfOnce - OP_BRA;
-
- /* For extended extraction brackets (large number), we have to fish out
- the number from a dummy opcode at the start. */
-
- if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX)
- stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->locals.instructionPtrAtStartOfOnce + 2 + LINK_SIZE);
- stack.currentFrame->locals.offset = stack.currentFrame->locals.number << 1;
-
-#ifdef DEBUG
- printf("end bracket %d", stack.currentFrame->locals.number);
- printf("\n");
-#endif
-
- /* Test for a numbered group. This includes groups called as a result
- of recursion. Note that whole-pattern recursion is coded as a recurse
- into group 0, so it won't be picked up here. Instead, we catch it when
- the OP_END is reached. */
-
- if (stack.currentFrame->locals.number > 0) {
- if (stack.currentFrame->locals.offset >= md.offsetMax)
- md.offsetOverflow = true;
- else {
- md.offsetVector[stack.currentFrame->locals.offset] =
- md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number];
- md.offsetVector[stack.currentFrame->locals.offset+1] = stack.currentFrame->args.subjectPtr - md.startSubject;
- if (stack.currentFrame->args.offsetTop <= stack.currentFrame->locals.offset)
- stack.currentFrame->args.offsetTop = stack.currentFrame->locals.offset + 2;
- }
- }
-
- /* For a non-repeating ket, just continue at this level. This also
- happens for a repeating ket if no characters were matched in the group.
- This is the forcible breaking of infinite loops as implemented in Perl
- 5.005. If there is an options reset, it will get obeyed in the normal
- course of events. */
-
- if (*stack.currentFrame->args.instructionPtr == OP_KET || stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
- stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE;
- NEXT_OPCODE;
- }
-
- /* The repeating kets try the rest of the pattern or restart from the
- preceding bracket, in the appropriate order. */
-
- if (*stack.currentFrame->args.instructionPtr == OP_KETRMIN) {
- RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- RECURSIVE_MATCH_NEW_GROUP(17, stack.currentFrame->locals.instructionPtrAtStartOfOnce, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- } else { /* OP_KETRMAX */
- RECURSIVE_MATCH_NEW_GROUP(18, stack.currentFrame->locals.instructionPtrAtStartOfOnce, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- }
- RRETURN;
-
- /* Start of subject. */
-
- BEGIN_OPCODE(CIRC):
- if (stack.currentFrame->args.subjectPtr != md.startSubject)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* After internal newline if multiline. */
-
- BEGIN_OPCODE(BOL):
- if (stack.currentFrame->args.subjectPtr != md.startSubject && !isNewline(stack.currentFrame->args.subjectPtr[-1]))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* End of subject. */
-
- BEGIN_OPCODE(DOLL):
- if (stack.currentFrame->args.subjectPtr < md.endSubject)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* Before internal newline if multiline. */
-
- BEGIN_OPCODE(EOL):
- if (stack.currentFrame->args.subjectPtr < md.endSubject && !isNewline(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* Word boundary assertions */
-
- BEGIN_OPCODE(NOT_WORD_BOUNDARY):
- BEGIN_OPCODE(WORD_BOUNDARY): {
- bool currentCharIsWordChar = false;
- bool previousCharIsWordChar = false;
-
- if (stack.currentFrame->args.subjectPtr > md.startSubject)
- previousCharIsWordChar = isWordChar(stack.currentFrame->args.subjectPtr[-1]);
- if (stack.currentFrame->args.subjectPtr < md.endSubject)
- currentCharIsWordChar = isWordChar(*stack.currentFrame->args.subjectPtr);
-
- /* Now see if the situation is what we want */
- bool wordBoundaryDesired = (*stack.currentFrame->args.instructionPtr++ == OP_WORD_BOUNDARY);
- if (wordBoundaryDesired ? currentCharIsWordChar == previousCharIsWordChar : currentCharIsWordChar != previousCharIsWordChar)
- RRETURN_NO_MATCH;
- NEXT_OPCODE;
- }
-
- /* Match a single character type; inline for speed */
-
- BEGIN_OPCODE(NOT_NEWLINE):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (isNewline(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(NOT_DIGIT):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (isASCIIDigit(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(DIGIT):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(NOT_WHITESPACE):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (isSpaceChar(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(WHITESPACE):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (!isSpaceChar(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(NOT_WORDCHAR):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (isWordChar(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(WORDCHAR):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (!isWordChar(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* Match a back reference, possibly repeatedly. Look past the end of the
- item to see if there is repeat information following. The code is similar
- to that for character classes, but repeated for efficiency. Then obey
- similar code to character type repeats - written out again for speed.
- However, if the referenced string is the empty string, always treat
- it as matched, any number of times (otherwise there could be infinite
- loops). */
-
- BEGIN_OPCODE(REF):
- stack.currentFrame->locals.offset = get2ByteValue(stack.currentFrame->args.instructionPtr + 1) << 1; /* Doubled ref number */
- stack.currentFrame->args.instructionPtr += 3; /* Advance past item */
-
- /* If the reference is unset, set the length to be longer than the amount
- of subject left; this ensures that every attempt at a match fails. We
- can't just fail here, because of the possibility of quantifiers with zero
- minima. */
-
- if (stack.currentFrame->locals.offset >= stack.currentFrame->args.offsetTop || md.offsetVector[stack.currentFrame->locals.offset] < 0)
- stack.currentFrame->locals.length = 0;
- else
- stack.currentFrame->locals.length = md.offsetVector[stack.currentFrame->locals.offset+1] - md.offsetVector[stack.currentFrame->locals.offset];
-
- /* Set up for repetition, or handle the non-repeated case */
-
- switch (*stack.currentFrame->args.instructionPtr) {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max);
- break;
-
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE);
- min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3);
- if (stack.currentFrame->locals.max == 0)
- stack.currentFrame->locals.max = INT_MAX;
- stack.currentFrame->args.instructionPtr += 5;
- break;
-
- default: /* No repeat follows */
- if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
- NEXT_OPCODE;
- }
-
- /* If the length of the reference is zero, just continue with the
- main loop. */
-
- if (stack.currentFrame->locals.length == 0)
- NEXT_OPCODE;
-
- /* First, ensure the minimum number of matches are present. */
-
- for (int i = 1; i <= min; i++) {
- if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
- }
-
- /* If min = max, continue at the same level without recursion.
- They are not both allowed to be zero. */
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- /* If minimizing, keep trying and advancing the pointer */
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(20, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || !matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
- RRETURN;
- stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
- }
- /* Control never reaches here */
- }
-
- /* If maximizing, find the longest string and work backwards */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
- break;
- stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
- }
- while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
- RECURSIVE_MATCH(21, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.subjectPtr -= stack.currentFrame->locals.length;
- }
- RRETURN_NO_MATCH;
- }
- /* Control never reaches here */
-
- /* Match a bit-mapped character class, possibly repeatedly. This op code is
- used when all the characters in the class have values in the range 0-255,
- and either the matching is caseful, or the characters are in the range
- 0-127 when UTF-8 processing is enabled. The only difference between
- OP_CLASS and OP_NCLASS occurs when a data character outside the range is
- encountered.
-
- First, look past the end of the item to see if there is repeat information
- following. Then obey similar code to character type repeats - written out
- again for speed. */
-
- BEGIN_OPCODE(NCLASS):
- BEGIN_OPCODE(CLASS):
- stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1; /* Save for matching */
- stack.currentFrame->args.instructionPtr += 33; /* Advance past the item */
-
- switch (*stack.currentFrame->args.instructionPtr) {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max);
- break;
-
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE);
- min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3);
- if (stack.currentFrame->locals.max == 0)
- stack.currentFrame->locals.max = INT_MAX;
- stack.currentFrame->args.instructionPtr += 5;
- break;
-
- default: /* No repeat follows */
- min = stack.currentFrame->locals.max = 1;
- break;
- }
-
- /* First, ensure the minimum number of matches are present. */
-
- for (int i = 1; i <= min; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (c > 255) {
- if (stack.currentFrame->locals.data[-1] == OP_CLASS)
- RRETURN_NO_MATCH;
- } else {
- if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7))))
- RRETURN_NO_MATCH;
- }
- }
-
- /* If max == min we can continue with the main loop without the
- need to recurse. */
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- /* If minimizing, keep testing the rest of the expression and advancing
- the pointer while it matches the class. */
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(22, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (c > 255) {
- if (stack.currentFrame->locals.data[-1] == OP_CLASS)
- RRETURN;
- } else {
- if ((stack.currentFrame->locals.data[c/8] & (1 << (c&7))) == 0)
- RRETURN;
- }
- }
- /* Control never reaches here */
- }
- /* If maximizing, find the longest possible run, then work backwards. */
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
-
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (c > 255) {
- if (stack.currentFrame->locals.data[-1] == OP_CLASS)
- break;
- } else {
- if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7))))
- break;
- }
- ++stack.currentFrame->args.subjectPtr;
- }
- for (;;) {
- RECURSIVE_MATCH(24, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
-
- RRETURN;
- }
- /* Control never reaches here */
-
- /* Match an extended character class. */
-
- BEGIN_OPCODE(XCLASS):
- stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE; /* Save for matching */
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); /* Advance past the item */
-
- switch (*stack.currentFrame->args.instructionPtr) {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max);
- break;
-
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE);
- min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3);
- if (stack.currentFrame->locals.max == 0)
- stack.currentFrame->locals.max = INT_MAX;
- stack.currentFrame->args.instructionPtr += 5;
- break;
-
- default: /* No repeat follows */
- min = stack.currentFrame->locals.max = 1;
- }
-
- /* First, ensure the minimum number of matches are present. */
-
- for (int i = 1; i <= min; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (!kjs_pcre_xclass(c, stack.currentFrame->locals.data))
- RRETURN_NO_MATCH;
- }
-
- /* If max == min we can continue with the main loop without the
- need to recurse. */
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- /* If minimizing, keep testing the rest of the expression and advancing
- the pointer while it matches the class. */
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(26, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (!kjs_pcre_xclass(c, stack.currentFrame->locals.data))
- RRETURN;
- }
- /* Control never reaches here */
- }
-
- /* If maximizing, find the longest possible run, then work backwards. */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (!kjs_pcre_xclass(c, stack.currentFrame->locals.data))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- for(;;) {
- RECURSIVE_MATCH(27, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
- RRETURN;
- }
-
- /* Control never reaches here */
-
- /* Match a single character, casefully */
-
- BEGIN_OPCODE(CHAR):
- stack.currentFrame->locals.length = 1;
- stack.currentFrame->args.instructionPtr++;
- getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length);
- stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length;
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (stack.currentFrame->locals.fc != *stack.currentFrame->args.subjectPtr++)
- RRETURN_NO_MATCH;
- NEXT_OPCODE;
-
- /* Match a single character, caselessly */
-
- BEGIN_OPCODE(CHAR_IGNORING_CASE): {
- stack.currentFrame->locals.length = 1;
- stack.currentFrame->args.instructionPtr++;
- getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length);
- stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length;
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- int dc = *stack.currentFrame->args.subjectPtr++;
- if (stack.currentFrame->locals.fc != dc && kjs_pcre_ucp_othercase(stack.currentFrame->locals.fc) != dc)
- RRETURN_NO_MATCH;
- NEXT_OPCODE;
- }
-
- /* Match a single ASCII character. */
-
- BEGIN_OPCODE(ASCII_CHAR):
- if (md.endSubject == stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->args.instructionPtr[1])
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- stack.currentFrame->args.instructionPtr += 2;
- NEXT_OPCODE;
-
- /* Match one of two cases of an ASCII letter. */
-
- BEGIN_OPCODE(ASCII_LETTER_IGNORING_CASE):
- if (md.endSubject == stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- if ((*stack.currentFrame->args.subjectPtr | 0x20) != stack.currentFrame->args.instructionPtr[1])
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- stack.currentFrame->args.instructionPtr += 2;
- NEXT_OPCODE;
-
- /* Match a single character repeatedly; different opcodes share code. */
-
- BEGIN_OPCODE(EXACT):
- min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = false;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATCHAR;
-
- BEGIN_OPCODE(UPTO):
- BEGIN_OPCODE(MINUPTO):
- min = 0;
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = *stack.currentFrame->args.instructionPtr == OP_MINUPTO;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATCHAR;
-
- BEGIN_OPCODE(STAR):
- BEGIN_OPCODE(MINSTAR):
- BEGIN_OPCODE(PLUS):
- BEGIN_OPCODE(MINPLUS):
- BEGIN_OPCODE(QUERY):
- BEGIN_OPCODE(MINQUERY):
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_STAR, minimize, min, stack.currentFrame->locals.max);
-
- /* Common code for all repeated single-character matches. We can give
- up quickly if there are fewer than the minimum number of characters left in
- the subject. */
-
- REPEATCHAR:
-
- stack.currentFrame->locals.length = 1;
- getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length);
- if (min * (stack.currentFrame->locals.fc > 0xFFFF ? 2 : 1) > md.endSubject - stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length;
-
- if (stack.currentFrame->locals.fc <= 0xFFFF) {
- int othercase = md.ignoreCase ? kjs_pcre_ucp_othercase(stack.currentFrame->locals.fc) : -1;
-
- for (int i = 1; i <= min; i++) {
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase)
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- if (minimize) {
- stack.currentFrame->locals.repeatOthercase = othercase;
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(28, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.repeatOthercase)
- RRETURN;
- ++stack.currentFrame->args.subjectPtr;
- }
- /* Control never reaches here */
- } else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase)
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
- RECURSIVE_MATCH(29, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- --stack.currentFrame->args.subjectPtr;
- }
- RRETURN_NO_MATCH;
- }
- /* Control never reaches here */
- } else {
- /* No case on surrogate pairs, so no need to bother with "othercase". */
-
- for (int i = 1; i <= min; i++) {
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.subjectPtr += 2;
- }
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(30, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc)
- RRETURN;
- stack.currentFrame->args.subjectPtr += 2;
- }
- /* Control never reaches here */
- } else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr > md.endSubject - 2)
- break;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc)
- break;
- stack.currentFrame->args.subjectPtr += 2;
- }
- while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
- RECURSIVE_MATCH(31, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.subjectPtr -= 2;
- }
- RRETURN_NO_MATCH;
- }
- /* Control never reaches here */
- }
- /* Control never reaches here */
-
- /* Match a negated single one-byte character. */
-
- BEGIN_OPCODE(NOT): {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- int b = stack.currentFrame->args.instructionPtr[1];
- int c = *stack.currentFrame->args.subjectPtr++;
- stack.currentFrame->args.instructionPtr += 2;
- if (md.ignoreCase) {
- if (c < 128)
- c = toLowerCase(c);
- if (toLowerCase(b) == c)
- RRETURN_NO_MATCH;
- } else {
- if (b == c)
- RRETURN_NO_MATCH;
- }
- NEXT_OPCODE;
- }
-
- /* Match a negated single one-byte character repeatedly. This is almost a
- repeat of the code for a repeated single character, but I haven't found a
- nice way of commoning these up that doesn't require a test of the
- positive/negative option for each character match. Maybe that wouldn't add
- very much to the time taken, but character matching *is* what this is all
- about... */
-
- BEGIN_OPCODE(NOTEXACT):
- min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = false;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATNOTCHAR;
-
- BEGIN_OPCODE(NOTUPTO):
- BEGIN_OPCODE(NOTMINUPTO):
- min = 0;
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = *stack.currentFrame->args.instructionPtr == OP_NOTMINUPTO;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATNOTCHAR;
-
- BEGIN_OPCODE(NOTSTAR):
- BEGIN_OPCODE(NOTMINSTAR):
- BEGIN_OPCODE(NOTPLUS):
- BEGIN_OPCODE(NOTMINPLUS):
- BEGIN_OPCODE(NOTQUERY):
- BEGIN_OPCODE(NOTMINQUERY):
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_NOTSTAR, minimize, min, stack.currentFrame->locals.max);
-
- /* Common code for all repeated single-byte matches. We can give up quickly
- if there are fewer than the minimum number of bytes left in the
- subject. */
-
- REPEATNOTCHAR:
- if (min > md.endSubject - stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- stack.currentFrame->locals.fc = *stack.currentFrame->args.instructionPtr++;
-
- /* The code is duplicated for the caseless and caseful cases, for speed,
- since matching characters is likely to be quite common. First, ensure the
- minimum number of matches are present. If min = max, continue at the same
- level without recursing. Otherwise, if minimizing, keep trying the rest of
- the expression and advancing one matching character if failing, up to the
- maximum. Alternatively, if maximizing, find the maximum number of
- characters and work backwards. */
-
- DPRINTF(("negative matching %c{%d,%d}\n", stack.currentFrame->locals.fc, min, stack.currentFrame->locals.max));
-
- if (md.ignoreCase) {
- if (stack.currentFrame->locals.fc < 128)
- stack.currentFrame->locals.fc = toLowerCase(stack.currentFrame->locals.fc);
-
- for (int i = 1; i <= min; i++) {
- int d = *stack.currentFrame->args.subjectPtr++;
- if (d < 128)
- d = toLowerCase(d);
- if (stack.currentFrame->locals.fc == d)
- RRETURN_NO_MATCH;
- }
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(38, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- int d = *stack.currentFrame->args.subjectPtr++;
- if (d < 128)
- d = toLowerCase(d);
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d)
- RRETURN;
- }
- /* Control never reaches here */
- }
-
- /* Maximize case */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
-
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int d = *stack.currentFrame->args.subjectPtr;
- if (d < 128)
- d = toLowerCase(d);
- if (stack.currentFrame->locals.fc == d)
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- for (;;) {
- RECURSIVE_MATCH(40, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
-
- RRETURN;
- }
- /* Control never reaches here */
- }
-
- /* Caseful comparisons */
-
- else {
- for (int i = 1; i <= min; i++) {
- int d = *stack.currentFrame->args.subjectPtr++;
- if (stack.currentFrame->locals.fc == d)
- RRETURN_NO_MATCH;
- }
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(42, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- int d = *stack.currentFrame->args.subjectPtr++;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d)
- RRETURN;
- }
- /* Control never reaches here */
- }
-
- /* Maximize case */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
-
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int d = *stack.currentFrame->args.subjectPtr;
- if (stack.currentFrame->locals.fc == d)
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- for (;;) {
- RECURSIVE_MATCH(44, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
-
- RRETURN;
- }
- }
- /* Control never reaches here */
-
- /* Match a single character type repeatedly; several different opcodes
- share code. This is very similar to the code for single characters, but we
- repeat it in the interests of efficiency. */
-
- BEGIN_OPCODE(TYPEEXACT):
- min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = true;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATTYPE;
-
- BEGIN_OPCODE(TYPEUPTO):
- BEGIN_OPCODE(TYPEMINUPTO):
- min = 0;
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = *stack.currentFrame->args.instructionPtr == OP_TYPEMINUPTO;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATTYPE;
-
- BEGIN_OPCODE(TYPESTAR):
- BEGIN_OPCODE(TYPEMINSTAR):
- BEGIN_OPCODE(TYPEPLUS):
- BEGIN_OPCODE(TYPEMINPLUS):
- BEGIN_OPCODE(TYPEQUERY):
- BEGIN_OPCODE(TYPEMINQUERY):
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_TYPESTAR, minimize, min, stack.currentFrame->locals.max);
-
- /* Common code for all repeated single character type matches. Note that
- in UTF-8 mode, '.' matches a character of any length, but for the other
- character types, the valid characters are all one-byte long. */
-
- REPEATTYPE:
- stack.currentFrame->locals.ctype = *stack.currentFrame->args.instructionPtr++; /* Code for the character type */
-
- /* First, ensure the minimum number of matches are present. Use inline
- code for maximizing the speed, and do the type test once at the start
- (i.e. keep it out of the loop). Also we can test that there are at least
- the minimum number of characters before we start. */
-
- if (min > md.endSubject - stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- if (min > 0) {
- switch (stack.currentFrame->locals.ctype) {
- case OP_NOT_NEWLINE:
- for (int i = 1; i <= min; i++) {
- if (isNewline(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_DIGIT:
- for (int i = 1; i <= min; i++) {
- if (isASCIIDigit(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_DIGIT:
- for (int i = 1; i <= min; i++) {
- if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_WHITESPACE:
- for (int i = 1; i <= min; i++) {
- if (isSpaceChar(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_WHITESPACE:
- for (int i = 1; i <= min; i++) {
- if (!isSpaceChar(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_WORDCHAR:
- for (int i = 1; i <= min; i++) {
- if (isWordChar(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_WORDCHAR:
- for (int i = 1; i <= min; i++) {
- if (!isWordChar(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- default:
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
- } /* End switch(stack.currentFrame->locals.ctype) */
- }
-
- /* If min = max, continue at the same level without recursing */
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- /* If minimizing, we have to test the rest of the pattern before each
- subsequent match. */
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(48, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
-
- int c = *stack.currentFrame->args.subjectPtr++;
- switch (stack.currentFrame->locals.ctype) {
- case OP_NOT_NEWLINE:
- if (isNewline(c))
- RRETURN;
- break;
-
- case OP_NOT_DIGIT:
- if (isASCIIDigit(c))
- RRETURN;
- break;
-
- case OP_DIGIT:
- if (!isASCIIDigit(c))
- RRETURN;
- break;
-
- case OP_NOT_WHITESPACE:
- if (isSpaceChar(c))
- RRETURN;
- break;
-
- case OP_WHITESPACE:
- if (!isSpaceChar(c))
- RRETURN;
- break;
-
- case OP_NOT_WORDCHAR:
- if (isWordChar(c))
- RRETURN;
- break;
-
- case OP_WORDCHAR:
- if (!isWordChar(c))
- RRETURN;
- break;
-
- default:
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
- }
- }
- /* Control never reaches here */
- }
-
- /* If maximizing it is worth using inline code for speed, doing the type
- test once at the start (i.e. keep it out of the loop). */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; /* Remember where we started */
-
- switch (stack.currentFrame->locals.ctype) {
- case OP_NOT_NEWLINE:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject || isNewline(*stack.currentFrame->args.subjectPtr))
- break;
- stack.currentFrame->args.subjectPtr++;
- }
- break;
-
- case OP_NOT_DIGIT:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (isASCIIDigit(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_DIGIT:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (!isASCIIDigit(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_WHITESPACE:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (isSpaceChar(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_WHITESPACE:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (!isSpaceChar(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_WORDCHAR:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (isWordChar(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_WORDCHAR:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (!isWordChar(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- default:
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
- }
-
- /* stack.currentFrame->args.subjectPtr is now past the end of the maximum run */
-
- for (;;) {
- RECURSIVE_MATCH(52, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
-
- /* Get here if we can't make it match with any permitted repetitions */
-
- RRETURN;
- }
- /* Control never reaches here */
-
- BEGIN_OPCODE(CRMINPLUS):
- BEGIN_OPCODE(CRMINQUERY):
- BEGIN_OPCODE(CRMINRANGE):
- BEGIN_OPCODE(CRMINSTAR):
- BEGIN_OPCODE(CRPLUS):
- BEGIN_OPCODE(CRQUERY):
- BEGIN_OPCODE(CRRANGE):
- BEGIN_OPCODE(CRSTAR):
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
-
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
- CAPTURING_BRACKET:
-#else
- default:
-#endif
- /* Opening capturing bracket. If there is space in the offset vector, save
- the current subject position in the working slot at the top of the vector. We
- mustn't change the current values of the data slot, because they may be set
- from a previous iteration of this group, and be referred to by a reference
- inside the group.
-
- If the bracket fails to match, we need to restore this value and also the
- values of the final offsets, in case they were set by a previous iteration of
- the same bracket.
-
- If there isn't enough space in the offset vector, treat this as if it were a
- non-capturing bracket. Don't worry about setting the flag for the error case
- here; that is handled in the code for KET. */
-
- ASSERT(*stack.currentFrame->args.instructionPtr > OP_BRA);
-
- stack.currentFrame->locals.number = *stack.currentFrame->args.instructionPtr - OP_BRA;
-
- /* For extended extraction brackets (large number), we have to fish out the
- number from a dummy opcode at the start. */
-
- if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX)
- stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->args.instructionPtr + 2 + LINK_SIZE);
- stack.currentFrame->locals.offset = stack.currentFrame->locals.number << 1;
-
-#ifdef DEBUG
- printf("start bracket %d subject=", stack.currentFrame->locals.number);
- pchars(stack.currentFrame->args.subjectPtr, 16, true, md);
- printf("\n");
-#endif
-
- if (stack.currentFrame->locals.offset < md.offsetMax) {
- stack.currentFrame->locals.saveOffset1 = md.offsetVector[stack.currentFrame->locals.offset];
- stack.currentFrame->locals.saveOffset2 = md.offsetVector[stack.currentFrame->locals.offset + 1];
- stack.currentFrame->locals.saveOffset3 = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number];
-
- DPRINTF(("saving %d %d %d\n", stack.currentFrame->locals.saveOffset1, stack.currentFrame->locals.saveOffset2, stack.currentFrame->locals.saveOffset3));
- md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->args.subjectPtr - md.startSubject;
-
- do {
- RECURSIVE_MATCH_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
-
- DPRINTF(("bracket %d failed\n", stack.currentFrame->locals.number));
-
- md.offsetVector[stack.currentFrame->locals.offset] = stack.currentFrame->locals.saveOffset1;
- md.offsetVector[stack.currentFrame->locals.offset + 1] = stack.currentFrame->locals.saveOffset2;
- md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->locals.saveOffset3;
-
- RRETURN;
- }
-
- /* Insufficient room for saving captured contents */
-
- goto NON_CAPTURING_BRACKET;
- }
-
- /* Do not stick any code in here without much thought; it is assumed
- that "continue" in the code above comes out to here to repeat the main
- loop. */
-
- } /* End of main loop */
-
- ASSERT_NOT_REACHED();
-
-#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-
-RRETURN_SWITCH:
- switch (stack.currentFrame->returnLocation) {
- case 0: goto RETURN;
- case 1: goto RRETURN_1;
- case 2: goto RRETURN_2;
- case 6: goto RRETURN_6;
- case 7: goto RRETURN_7;
- case 14: goto RRETURN_14;
- case 15: goto RRETURN_15;
- case 16: goto RRETURN_16;
- case 17: goto RRETURN_17;
- case 18: goto RRETURN_18;
- case 19: goto RRETURN_19;
- case 20: goto RRETURN_20;
- case 21: goto RRETURN_21;
- case 22: goto RRETURN_22;
- case 24: goto RRETURN_24;
- case 26: goto RRETURN_26;
- case 27: goto RRETURN_27;
- case 28: goto RRETURN_28;
- case 29: goto RRETURN_29;
- case 30: goto RRETURN_30;
- case 31: goto RRETURN_31;
- case 38: goto RRETURN_38;
- case 40: goto RRETURN_40;
- case 42: goto RRETURN_42;
- case 44: goto RRETURN_44;
- case 48: goto RRETURN_48;
- case 52: goto RRETURN_52;
- }
-
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
-
-#endif
-
-RETURN:
- return isMatch;
-}
-
-
-/*************************************************
-* Execute a Regular Expression *
-*************************************************/
-
-/* This function applies a compiled re to a subject string and picks out
-portions of the string if it matches. Two elements in the vector are set for
-each substring: the offsets to the start and end of the substring.
-
-Arguments:
- re points to the compiled expression
- extra_data points to extra data or is NULL
- subject points to the subject string
- length length of subject string (may contain binary zeros)
- start_offset where to start in the subject string
- options option bits
- offsets points to a vector of ints to be filled in with offsets
- offsetCount the number of elements in the vector
-
-Returns: > 0 => success; value is the number of elements filled in
- = 0 => success, but offsets is not big enough
- -1 => failed to match
- < -1 => some kind of unexpected problem
-*/
-
-static void tryFirstByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int firstByte, bool firstByteIsCaseless, bool useMultiLineFirstCharOptimization, const UChar* originalSubjectStart)
-{
- // If firstByte is set, try scanning to the first instance of that byte
- // no need to try and match against any earlier part of the subject string.
- if (firstByte >= 0) {
- UChar firstChar = firstByte;
- if (firstByteIsCaseless)
- while (subjectPtr < endSubject) {
- int c = *subjectPtr;
- if (c > 127)
- break;
- if (toLowerCase(c) == firstChar)
- break;
- subjectPtr++;
- }
- else {
- while (subjectPtr < endSubject && *subjectPtr != firstChar)
- subjectPtr++;
- }
- } else if (useMultiLineFirstCharOptimization) {
- /* Or to just after \n for a multiline match if possible */
- // I'm not sure why this != originalSubjectStart check is necessary -- ecs 11/18/07
- if (subjectPtr > originalSubjectStart) {
- while (subjectPtr < endSubject && !isNewline(subjectPtr[-1]))
- subjectPtr++;
- }
- }
-}
-
-static bool tryRequiredByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int reqByte, int reqByte2, bool reqByteIsCaseless, bool hasFirstByte, const UChar*& reqBytePtr)
-{
- /* If reqByte is set, we know that that character must appear in the subject
- for the match to succeed. If the first character is set, reqByte must be
- later in the subject; otherwise the test starts at the match point. This
- optimization can save a huge amount of backtracking in patterns with nested
- unlimited repeats that aren't going to match. Writing separate code for
- cased/caseless versions makes it go faster, as does using an autoincrement
- and backing off on a match.
-
- HOWEVER: when the subject string is very, very long, searching to its end can
- take a long time, and give bad performance on quite ordinary patterns. This
- showed up when somebody was matching /^C/ on a 32-megabyte string... so we
- don't do this when the string is sufficiently long.
- */
-
- if (reqByte >= 0 && endSubject - subjectPtr < REQ_BYTE_MAX) {
- const UChar* p = subjectPtr + (hasFirstByte ? 1 : 0);
-
- /* We don't need to repeat the search if we haven't yet reached the
- place we found it at last time. */
-
- if (p > reqBytePtr) {
- if (reqByteIsCaseless) {
- while (p < endSubject) {
- int pp = *p++;
- if (pp == reqByte || pp == reqByte2) {
- p--;
- break;
- }
- }
- } else {
- while (p < endSubject) {
- if (*p++ == reqByte) {
- p--;
- break;
- }
- }
- }
-
- /* If we can't find the required character, break the matching loop */
-
- if (p >= endSubject)
- return true;
-
- /* If we have found the required character, save the point where we
- found it, so that we don't search again next time round the loop if
- the start hasn't passed this character yet. */
-
- reqBytePtr = p;
- }
- }
- return false;
-}
-
-int jsRegExpExecute(const JSRegExp* re,
- const UChar* subject, int length, int start_offset, int* offsets,
- int offsetCount)
-{
- ASSERT(re);
- ASSERT(subject || !length);
- ASSERT(offsetCount >= 0);
- ASSERT(offsets || offsetCount == 0);
-
- HistogramTimeLogger logger(re);
-
- MatchData matchBlock;
- matchBlock.startSubject = subject;
- matchBlock.endSubject = matchBlock.startSubject + length;
- const UChar* endSubject = matchBlock.endSubject;
-
- matchBlock.multiline = (re->options & MatchAcrossMultipleLinesOption);
- matchBlock.ignoreCase = (re->options & IgnoreCaseOption);
-
- /* If the expression has got more back references than the offsets supplied can
- hold, we get a temporary chunk of working store to use during the matching.
- Otherwise, we can use the vector supplied, rounding down its size to a multiple
- of 3. */
-
- int ocount = offsetCount - (offsetCount % 3);
-
- // FIXME: This is lame that we have to second-guess our caller here.
- // The API should change to either fail-hard when we don't have enough offset space
- // or that we shouldn't ask our callers to pre-allocate in the first place.
- bool usingTemporaryOffsets = false;
- if (re->topBackref > 0 && re->topBackref >= ocount/3) {
- ocount = re->topBackref * 3 + 3;
- matchBlock.offsetVector = new int[ocount];
- if (!matchBlock.offsetVector)
- return JSRegExpErrorNoMemory;
- usingTemporaryOffsets = true;
- } else
- matchBlock.offsetVector = offsets;
-
- matchBlock.offsetEnd = ocount;
- matchBlock.offsetMax = (2*ocount)/3;
- matchBlock.offsetOverflow = false;
-
- /* Compute the minimum number of offsets that we need to reset each time. Doing
- this makes a huge difference to execution time when there aren't many brackets
- in the pattern. */
-
- int resetCount = 2 + re->topBracket * 2;
- if (resetCount > offsetCount)
- resetCount = ocount;
-
- /* Reset the working variable associated with each extraction. These should
- never be used unless previously set, but they get saved and restored, and so we
- initialize them to avoid reading uninitialized locations. */
-
- if (matchBlock.offsetVector) {
- int* iptr = matchBlock.offsetVector + ocount;
- int* iend = iptr - resetCount/2 + 1;
- while (--iptr >= iend)
- *iptr = -1;
- }
-
- /* Set up the first character to match, if available. The firstByte value is
- never set for an anchored regular expression, but the anchoring may be forced
- at run time, so we have to test for anchoring. The first char may be unset for
- an unanchored pattern, of course. If there's no first char and the pattern was
- studied, there may be a bitmap of possible first characters. */
-
- bool firstByteIsCaseless = false;
- int firstByte = -1;
- if (re->options & UseFirstByteOptimizationOption) {
- firstByte = re->firstByte & 255;
- if ((firstByteIsCaseless = (re->firstByte & REQ_IGNORE_CASE)))
- firstByte = toLowerCase(firstByte);
- }
-
- /* For anchored or unanchored matches, there may be a "last known required
- character" set. */
-
- bool reqByteIsCaseless = false;
- int reqByte = -1;
- int reqByte2 = -1;
- if (re->options & UseRequiredByteOptimizationOption) {
- reqByte = re->reqByte & 255; // FIXME: This optimization could be made to work for UTF16 chars as well...
- reqByteIsCaseless = (re->reqByte & REQ_IGNORE_CASE);
- reqByte2 = flipCase(reqByte);
- }
-
- /* Loop for handling unanchored repeated matching attempts; for anchored regexs
- the loop runs just once. */
-
- const UChar* startMatch = subject + start_offset;
- const UChar* reqBytePtr = startMatch - 1;
- bool useMultiLineFirstCharOptimization = re->options & UseMultiLineFirstByteOptimizationOption;
-
- do {
- /* Reset the maximum number of extractions we might see. */
- if (matchBlock.offsetVector) {
- int* iptr = matchBlock.offsetVector;
- int* iend = iptr + resetCount;
- while (iptr < iend)
- *iptr++ = -1;
- }
-
- tryFirstByteOptimization(startMatch, endSubject, firstByte, firstByteIsCaseless, useMultiLineFirstCharOptimization, matchBlock.startSubject + start_offset);
- if (tryRequiredByteOptimization(startMatch, endSubject, reqByte, reqByte2, reqByteIsCaseless, firstByte >= 0, reqBytePtr))
- break;
-
- /* When a match occurs, substrings will be set for all internal extractions;
- we just need to set up the whole thing as substring 0 before returning. If
- there were too many extractions, set the return code to zero. In the case
- where we had to get some local store to hold offsets for backreferences, copy
- those back references that we can. In this case there need not be overflow
- if certain parts of the pattern were not used. */
-
- /* The code starts after the JSRegExp block and the capture name table. */
- const unsigned char* start_code = (const unsigned char*)(re + 1);
-
- int returnCode = match(startMatch, start_code, 2, matchBlock);
-
- /* When the result is no match, advance the pointer to the next character
- and continue. */
- if (returnCode == 0) {
- startMatch++;
- continue;
- }
-
- if (returnCode != 1) {
- ASSERT(returnCode == JSRegExpErrorHitLimit || returnCode == JSRegExpErrorNoMemory);
- DPRINTF((">>>> error: returning %d\n", returnCode));
- return returnCode;
- }
-
- /* We have a match! Copy the offset information from temporary store if
- necessary */
-
- if (usingTemporaryOffsets) {
- if (offsetCount >= 4) {
- memcpy(offsets + 2, matchBlock.offsetVector + 2, (offsetCount - 2) * sizeof(int));
- DPRINTF(("Copied offsets from temporary memory\n"));
- }
- if (matchBlock.endOffsetTop > offsetCount)
- matchBlock.offsetOverflow = true;
-
- DPRINTF(("Freeing temporary memory\n"));
- delete [] matchBlock.offsetVector;
- }
-
- returnCode = matchBlock.offsetOverflow ? 0 : matchBlock.endOffsetTop / 2;
-
- if (offsetCount < 2)
- returnCode = 0;
- else {
- offsets[0] = startMatch - matchBlock.startSubject;
- offsets[1] = matchBlock.endMatchPtr - matchBlock.startSubject;
- }
-
- DPRINTF((">>>> returning %d\n", returnCode));
- return returnCode;
- } while (!(re->options & IsAnchoredOption) && startMatch <= endSubject);
-
- if (usingTemporaryOffsets) {
- DPRINTF(("Freeing temporary memory\n"));
- delete [] matchBlock.offsetVector;
- }
-
- DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n"));
- return JSRegExpErrorNoMatch;
-}
-
-#if REGEXP_HISTOGRAM
-
-class CompareHistogramEntries {
-public:
- bool operator()(const pair<UString, double>& a, const pair<UString, double>& b)
- {
- if (a.second == b.second)
- return a.first < b.first;
- return a.second < b.second;
- }
-};
-
-Histogram::~Histogram()
-{
- Vector<pair<UString, double> > values;
- Map::iterator end = times.end();
- for (Map::iterator it = times.begin(); it != end; ++it)
- values.append(*it);
- sort(values.begin(), values.end(), CompareHistogramEntries());
- size_t size = values.size();
- printf("Regular Expressions, sorted by time spent evaluating them:\n");
- for (size_t i = 0; i < size; ++i)
- printf(" %f - %s\n", values[size - i - 1].second, values[size - i - 1].first.UTF8String().c_str());
-}
-
-void Histogram::add(const JSRegExp* re, double elapsedTime)
-{
- UString string(reinterpret_cast<const UChar*>(reinterpret_cast<const char*>(re) + re->stringOffset), re->stringLength);
- if (re->options & IgnoreCaseOption && re->options & MatchAcrossMultipleLinesOption)
- string += " (multi-line, ignore case)";
- else {
- if (re->options & IgnoreCaseOption)
- string += " (ignore case)";
- if (re->options & MatchAcrossMultipleLinesOption)
- string += " (multi-line)";
- }
- pair<Map::iterator, bool> result = times.add(string.rep(), elapsedTime);
- if (!result.second)
- result.first->second += elapsedTime;
-}
-
-HistogramTimeLogger::HistogramTimeLogger(const JSRegExp* re)
- : m_re(re)
- , m_startTime(getCurrentUTCTimeWithMicroseconds())
-{
-}
-
-HistogramTimeLogger::~HistogramTimeLogger()
-{
- static Histogram histogram;
- histogram.add(m_re, getCurrentUTCTimeWithMicroseconds() - m_startTime);
-}
-
-#endif