Example #1
0
PassRefPtr<Element> SelectorDataList::queryFirst(Node* rootNode) const
{
    Vector<RefPtr<Node> > result;
    execute<true>(rootNode, result);
    if (result.isEmpty())
        return 0;
    ASSERT(result.size() == 1);
    ASSERT(result.first()->isElementNode());
    return static_cast<Element*>(result.first().get());
}
Example #2
0
void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
{
    // http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#dom-form-nameditem
    elements()->namedItems(name, namedItems);

    Node* elementFromPast = elementFromPastNamesMap(name);
    if (namedItems.size() && namedItems.first() != elementFromPast)
        addToPastNamesMap(namedItems.first().get(), name);
    else if (elementFromPast && namedItems.isEmpty())
        namedItems.append(elementFromPast);
}
Example #3
0
void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
{
    // http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#dom-form-nameditem
    elements()->namedItems(name, namedItems);

    // FIXME: The specification says we should not add the element from the past when names map when namedItems is not empty.
    HTMLFormControlElement* elementFromPast = elementFromPastNamesMap(name);
    if (namedItems.size() == 1 && namedItems.first() != elementFromPast)
        addElementToPastNamesMap(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
    else if (elementFromPast && namedItems.find(elementFromPast) == notFound)
        namedItems.append(elementFromPast);
}
// FIXME: Use Ref<HTMLElement> for the function result since there are no non-HTML elements returned here.
Vector<Ref<Element>> HTMLFormElement::namedElements(const AtomicString& name)
{
    // http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#dom-form-nameditem
    Vector<Ref<Element>> namedItems = elements()->namedItems(name);

    HTMLElement* elementFromPast = elementFromPastNamesMap(name);
    if (namedItems.size() == 1 && namedItems.first().ptr() != elementFromPast)
        addToPastNamesMap(downcast<HTMLElement>(namedItems.first().get()).asFormNamedItem(), name);
    else if (elementFromPast && namedItems.isEmpty())
        namedItems.append(*elementFromPast);

    return namedItems;
}
Example #5
0
LayoutType closestSnapOffset(const Vector<LayoutType>& snapOffsets, const Vector<ScrollOffsetRange<LayoutType>>& snapOffsetRanges, LayoutType scrollDestination, float velocity, unsigned& activeSnapIndex)
{
    ASSERT(snapOffsets.size());
    activeSnapIndex = 0;

    unsigned lowerSnapOffsetRangeIndex;
    unsigned upperSnapOffsetRangeIndex;
    indicesOfNearestSnapOffsetRanges<LayoutType>(scrollDestination, snapOffsetRanges, lowerSnapOffsetRangeIndex, upperSnapOffsetRangeIndex);
    if (lowerSnapOffsetRangeIndex == upperSnapOffsetRangeIndex && upperSnapOffsetRangeIndex != invalidSnapOffsetIndex) {
        activeSnapIndex = invalidSnapOffsetIndex;
        return scrollDestination;
    }

    if (scrollDestination <= snapOffsets.first())
        return snapOffsets.first();

    activeSnapIndex = snapOffsets.size() - 1;
    if (scrollDestination >= snapOffsets.last())
        return snapOffsets.last();

    unsigned lowerIndex;
    unsigned upperIndex;
    indicesOfNearestSnapOffsets<LayoutType>(scrollDestination, snapOffsets, lowerIndex, upperIndex);
    LayoutType lowerSnapPosition = snapOffsets[lowerIndex];
    LayoutType upperSnapPosition = snapOffsets[upperIndex];
    if (!std::abs(velocity)) {
        bool isCloserToLowerSnapPosition = scrollDestination - lowerSnapPosition <= upperSnapPosition - scrollDestination;
        activeSnapIndex = isCloserToLowerSnapPosition ? lowerIndex : upperIndex;
        return isCloserToLowerSnapPosition ? lowerSnapPosition : upperSnapPosition;
    }

    // Non-zero velocity indicates a flick gesture. Even if another snap point is closer, we should choose the one in the direction of the flick gesture
    // as long as a scroll snap offset range does not lie between the scroll destination and the targeted snap offset.
    if (velocity < 0) {
        if (lowerSnapOffsetRangeIndex != invalidSnapOffsetIndex && lowerSnapPosition < snapOffsetRanges[lowerSnapOffsetRangeIndex].end) {
            activeSnapIndex = upperIndex;
            return upperSnapPosition;
        }
        activeSnapIndex = lowerIndex;
        return lowerSnapPosition;
    }

    if (upperSnapOffsetRangeIndex != invalidSnapOffsetIndex && snapOffsetRanges[upperSnapOffsetRangeIndex].start < upperSnapPosition) {
        activeSnapIndex = lowerIndex;
        return lowerSnapPosition;
    }
    activeSnapIndex = upperIndex;
    return upperSnapPosition;
}
Example #6
0
SimpleFontData::SimpleFontData(PassOwnPtr<SVGFontData> svgFontData, int size, bool syntheticBold, bool syntheticItalic)
    : m_orientation(Horizontal)
    , m_platformData(FontPlatformData(size, syntheticBold, syntheticItalic))
    , m_treatAsFixedPitch(false)
    , m_svgFontData(svgFontData)
    , m_isCustomFont(true)
    , m_isLoading(false)
    , m_isBrokenIdeographFont(false)
{
    SVGFontFaceElement* svgFontFaceElement = m_svgFontData->svgFontFaceElement();
    unsigned unitsPerEm = svgFontFaceElement->unitsPerEm();

    float scale = size;
    if (unitsPerEm)
        scale /= unitsPerEm;

    float xHeight = svgFontFaceElement->xHeight() * scale;
    float ascent = svgFontFaceElement->ascent() * scale;
    float descent = svgFontFaceElement->descent() * scale;
    float lineGap = 0.1f * size;
    m_fontMetrics.setUnitsPerEm(unitsPerEm);
    m_fontMetrics.setAscent(ascent);
    m_fontMetrics.setDescent(descent);
    m_fontMetrics.setLineGap(lineGap);
    m_fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap));
    m_fontMetrics.setXHeight(xHeight);

    SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();

    Vector<SVGGlyphIdentifier> spaceGlyphs;
    associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs);
    m_spaceWidth = spaceGlyphs.isEmpty() ? xHeight : spaceGlyphs.first().horizontalAdvanceX * scale;

    Vector<SVGGlyphIdentifier> numeralZeroGlyphs;
    associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs);
    m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : numeralZeroGlyphs.first().horizontalAdvanceX * scale;

    Vector<SVGGlyphIdentifier> letterWGlyphs;
    associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs);
    m_maxCharWidth = letterWGlyphs.isEmpty() ? ascent : letterWGlyphs.first().horizontalAdvanceX * scale;

    // FIXME: is there a way we can get the space glyph from the SVGGlyphIdentifier above?
    m_spaceGlyph = 0;
    m_zeroWidthSpaceGlyph = 0;
    determinePitch();
    m_adjustedSpaceWidth = roundf(m_spaceWidth);
    m_missingGlyphData.fontData = this;
    m_missingGlyphData.glyph = 0;
}
void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
{
    elements()->namedItems(name, namedItems);

    HTMLFormControlElement* aliasElement = elementForAlias(name);
    if (aliasElement) {
        if (namedItems.find(aliasElement) == notFound) {
            // We have seen it before but it is gone now. Still, we need to return it.
            // FIXME: The above comment is not clear enough; it does not say why we need to do this.
            namedItems.append(aliasElement);
        }
    }
    if (namedItems.size() && namedItems.first() != aliasElement)
        addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
}
Example #8
0
static void indicesOfNearestSnapOffsetRanges(LayoutType offset, const Vector<ScrollOffsetRange<LayoutType>>& snapOffsetRanges, unsigned& lowerIndex, unsigned& upperIndex)
{
    if (snapOffsetRanges.isEmpty()) {
        lowerIndex = invalidSnapOffsetIndex;
        upperIndex = invalidSnapOffsetIndex;
        return;
    }

    int lowerIndexAsInt = -1;
    int upperIndexAsInt = snapOffsetRanges.size();
    do {
        int middleIndex = (lowerIndexAsInt + upperIndexAsInt) / 2;
        auto& range = snapOffsetRanges[middleIndex];
        if (range.start < offset && offset < range.end) {
            lowerIndexAsInt = middleIndex;
            upperIndexAsInt = middleIndex;
            break;
        }

        if (offset > range.end)
            lowerIndexAsInt = middleIndex;
        else
            upperIndexAsInt = middleIndex;
    } while (lowerIndexAsInt < upperIndexAsInt - 1);

    if (offset <= snapOffsetRanges.first().start)
        lowerIndex = invalidSnapOffsetIndex;
    else
        lowerIndex = lowerIndexAsInt;

    if (offset >= snapOffsetRanges.last().end)
        upperIndex = invalidSnapOffsetIndex;
    else
        upperIndex = upperIndexAsInt;
}
Example #9
0
// Fills bounds with points from argv starting at firstCoord; also resizes selected to match the size of bounds
static void readPolyBounds(S32 argc, const char **argv, S32 firstCoord, F32 gridSize, 
                           bool allowFirstAndLastPointToBeEqual, Vector<Point> &bounds, Vector<bool> &selected)
{
   Point p, lastP;
   
   bool isTwoPointLine = (argc - firstCoord) / 2 == 2;
   
   bounds.clear();

   // Make sure we don't crash with firstCoord = 0; argc = 7; or some uneven number
   for(S32 i = firstCoord; i < argc - 1; i += 2)
   {
      // If we are loading legacy levels (earlier than 019), then we have a gridsize multiplier
      if(gridSize != 1.f)
         p.set( (F32) (atof(argv[i]) * gridSize), (F32) (atof(argv[i+1]) * gridSize ) );
      else
         p.set( (F32) atof(argv[i]), (F32) atof(argv[i+1]));

      // Normally, we'll want to filter out adjacent points that are identical.  But we also
      // need to handle the situation where the user has created a 2-pt 0-length line.
      // Because the users demand it.  We will deliver.
      if(i == firstCoord || p != lastP || isTwoPointLine)
         bounds.push_back(p);

      lastP.set(p);
   }

   // Check if last point was same as first; if so, scrap it
   if(!allowFirstAndLastPointToBeEqual && bounds.first() == bounds.last())
      bounds.erase(bounds.size() - 1);

   selected.resize(bounds.size());
}
PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* exec, JSC::JSValue& exception, size_t maxStackSize)
{
    Vector<ScriptCallFrame> frames;
    RefCountedArray<StackFrame> stackTrace = exec->vm().exceptionStack();
    for (size_t i = 0; i < stackTrace.size() && i < maxStackSize; i++) {
        if (!stackTrace[i].callee && frames.size())
            break;

        String functionName = stackTrace[i].friendlyFunctionName(exec);
        unsigned line;
        unsigned column;
        stackTrace[i].computeLineAndColumn(line, column);
        frames.append(ScriptCallFrame(functionName, stackTrace[i].sourceURL, line, column));
    }

    // FIXME: <http://webkit.org/b/115087> Web Inspector: WebCore::reportException should not evaluate JavaScript handling exceptions
    // Fallback to getting at least the line and sourceURL from the exception if it has values and the exceptionStack doesn't.
    if (frames.size() > 0) {
        const ScriptCallFrame& firstCallFrame = frames.first();
        JSObject* exceptionObject = exception.toObject(exec);
        if (exception.isObject() && firstCallFrame.sourceURL().isEmpty()) {
            JSValue lineValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "line"));
            int lineNumber = lineValue && lineValue.isNumber() ? int(lineValue.toNumber(exec)) : 0;
            JSValue sourceURLValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "sourceURL"));
            String exceptionSourceURL = sourceURLValue && sourceURLValue.isString() ? sourceURLValue.toString(exec)->value(exec) : ASCIILiteral("undefined");
            frames[0] = ScriptCallFrame(firstCallFrame.functionName(), exceptionSourceURL, lineNumber, 0);
        }
    }

    return ScriptCallStack::create(frames);
}
Example #11
0
SimpleFontData::SimpleFontData(PassOwnPtr<SVGFontData> svgFontData, int size, bool syntheticBold, bool syntheticItalic)
    : m_orientation(Horizontal)
    , m_platformData(FontPlatformData(size, syntheticBold, syntheticItalic))
    , m_treatAsFixedPitch(false)
    , m_svgFontData(svgFontData)
    , m_isCustomFont(true)
    , m_isLoading(false)
    , m_isBrokenIdeographFont(false)
{
    SVGFontFaceElement* svgFontFaceElement = m_svgFontData->svgFontFaceElement();
    m_unitsPerEm = svgFontFaceElement->unitsPerEm();

    double scale = size;
    if (m_unitsPerEm)
        scale /= m_unitsPerEm;

    m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale);
    m_descent = static_cast<int>(svgFontFaceElement->descent() * scale);
    m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale);
    m_lineGap = 0.1f * size;
    m_lineSpacing = m_ascent + m_descent + m_lineGap;

    SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();

    Vector<SVGGlyphIdentifier> spaceGlyphs;
    associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs);
    m_spaceWidth = spaceGlyphs.isEmpty() ? m_xHeight : static_cast<float>(spaceGlyphs.first().horizontalAdvanceX * scale);

    Vector<SVGGlyphIdentifier> numeralZeroGlyphs;
    associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs);
    m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : static_cast<float>(numeralZeroGlyphs.first().horizontalAdvanceX * scale);

    Vector<SVGGlyphIdentifier> letterWGlyphs;
    associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs);
    m_maxCharWidth = letterWGlyphs.isEmpty() ? m_ascent : static_cast<float>(letterWGlyphs.first().horizontalAdvanceX * scale);

    // FIXME: is there a way we can get the space glyph from the SVGGlyphIdentifier above?
    m_spaceGlyph = 0;
    m_zeroWidthSpaceGlyph = 0;
    determinePitch();
    m_adjustedSpaceWidth = roundf(m_spaceWidth);
    m_missingGlyphData.fontData = this;
    m_missingGlyphData.glyph = 0;
}
Element* HTMLCollection::namedItem(const AtomicString& name) const
{
    // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/nameditem.asp
    // This method first searches for an object with a matching id
    // attribute. If a match is not found, the method then searches for an
    // object with a matching name attribute, but only on those elements
    // that are allowed a name attribute.
    updateIdNameCache();

    Vector<Element*>* idResults = idCache(name);
    if (idResults && !idResults->isEmpty())
        return idResults->first();

    Vector<Element*>* nameResults = nameCache(name);
    if (nameResults && !nameResults->isEmpty())
        return nameResults->first();

    return 0;
}
Example #13
0
static void adjustAxisSnapOffsetsForScrollExtent(Vector<LayoutUnit>& snapOffsets, float maxScrollExtent)
{
    if (snapOffsets.isEmpty())
        return;

    std::sort(snapOffsets.begin(), snapOffsets.end());
    if (snapOffsets.last() != maxScrollExtent)
        snapOffsets.append(maxScrollExtent);
    if (snapOffsets.first())
        snapOffsets.insert(0, 0);
}
Example #14
0
void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
{
    elements()->namedItems(name, namedItems);

    // see if we have seen something with this name before
    RefPtr<HTMLFormControlElement> aliasElem;
    if ((aliasElem = elementForAlias(name))) {
        bool found = false;
        for (unsigned n = 0; n < namedItems.size(); n++) {
            if (namedItems[n] == aliasElem.get()) {
                found = true;
                break;
            }
        }
        if (!found)
            // we have seen it before but it is gone now. still, we need to return it.
            namedItems.append(aliasElem.get());
    }
    // name has been accessed, remember it
    if (namedItems.size() && aliasElem != namedItems.first())
        addElementAlias(static_cast<HTMLFormControlElement*>(namedItems.first().get()), name);
}
void HTMLFormControlsCollection::namedGetter(const AtomicString& name, bool& radioNodeListEnabled, RefPtr<RadioNodeList>& radioNodeList, bool& elementEnabled, RefPtr<Element>& element)
{
    Vector<RefPtr<Element> > namedItems;
    this->namedItems(name, namedItems);

    if (namedItems.isEmpty())
        return;

    if (namedItems.size() == 1) {
        elementEnabled = true;
        element = namedItems.first();
        return;
    }

    radioNodeListEnabled = true;
    radioNodeList = ownerNode().radioNodeList(name);
}
static void updateFromStyle(Vector<LayoutUnit>& snapOffsets, const RenderStyle& style, ScrollEventAxis axis, LayoutUnit viewSize, LayoutUnit scrollSize, Vector<LayoutUnit>& snapOffsetSubsequence)
{
    std::sort(snapOffsetSubsequence.begin(), snapOffsetSubsequence.end());
    if (snapOffsetSubsequence.isEmpty())
        snapOffsetSubsequence.append(0);

    auto* points = (axis == ScrollEventAxis::Horizontal) ? style.scrollSnapPointsX() : style.scrollSnapPointsY();
    bool hasRepeat = points ? points->hasRepeat : false;
    LayoutUnit repeatOffset = points ? valueForLength(points->repeatOffset, viewSize) : LayoutUnit::fromPixel(1);
    repeatOffset = std::max<LayoutUnit>(repeatOffset, LayoutUnit::fromPixel(1));
    
    LayoutUnit destinationOffset = destinationOffsetForViewSize(axis, style.scrollSnapDestination(), viewSize);
    LayoutUnit curSnapPositionShift = 0;
    LayoutUnit maxScrollOffset = scrollSize - viewSize;
    LayoutUnit lastSnapPosition = curSnapPositionShift;
    do {
        for (auto& snapPosition : snapOffsetSubsequence) {
            LayoutUnit potentialSnapPosition = curSnapPositionShift + snapPosition - destinationOffset;
            if (potentialSnapPosition < 0)
                continue;

            if (potentialSnapPosition >= maxScrollOffset)
                break;

            // Don't add another zero offset value.
            if (potentialSnapPosition)
                snapOffsets.append(potentialSnapPosition);

            lastSnapPosition = potentialSnapPosition + destinationOffset;
        }
        curSnapPositionShift = lastSnapPosition + repeatOffset;
    } while (hasRepeat && curSnapPositionShift < maxScrollOffset);

    if (snapOffsets.isEmpty())
        return;

    // Always put a snap point on the zero offset.
    if (snapOffsets.first())
        snapOffsets.insert(0, 0);

    // Always put a snap point on the maximum scroll offset.
    // Not a part of the spec, but necessary to prevent unreachable content when snapping.
    if (snapOffsets.last() != maxScrollOffset)
        snapOffsets.append(maxScrollOffset);
}
Example #17
0
static void printTransitions(const DFA& dfa, unsigned sourceNodeId)
{
    const DFANode& sourceNode = dfa.nodes[sourceNodeId];
    auto transitions = sourceNode.transitions(dfa);

    if (transitions.begin() == transitions.end())
        return;

    HashMap<unsigned, Vector<uint16_t>, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> transitionsPerTarget;

    // First, we build the list of transitions coming to each target node.
    for (const auto& transition : transitions) {
        unsigned target = transition.target();
        transitionsPerTarget.add(target, Vector<uint16_t>());

        for (unsigned offset = 0; offset < transition.range().size(); ++offset)
            transitionsPerTarget.find(target)->value.append(transition.first() + offset);
    }

    // Then we go over each one an display the ranges one by one.
    for (const auto& transitionPerTarget : transitionsPerTarget) {
        dataLogF("        %d -> %d [label=\"", sourceNodeId, transitionPerTarget.key);

        Vector<uint16_t> incommingCharacters = transitionPerTarget.value;
        std::sort(incommingCharacters.begin(), incommingCharacters.end());

        char rangeStart = incommingCharacters.first();
        char rangeEnd = rangeStart;
        bool first = true;
        for (unsigned sortedTransitionIndex = 1; sortedTransitionIndex < incommingCharacters.size(); ++sortedTransitionIndex) {
            char nextChar = incommingCharacters[sortedTransitionIndex];
            if (nextChar == rangeEnd+1) {
                rangeEnd = nextChar;
                continue;
            }
            printRange(first, rangeStart, rangeEnd);
            rangeStart = rangeEnd = nextChar;
            first = false;
        }
        printRange(first, rangeStart, rangeEnd);

        dataLogF("\"];\n");
    }
}
Example #18
0
static void printTransitions(const Vector<NFANode>& graph, unsigned sourceNode, uint16_t epsilonTransitionCharacter)
{
    const NFANode& node = graph[sourceNode];
    const HashMap<uint16_t, NFANodeIndexSet, DefaultHash<uint16_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint16_t>>& transitions = node.transitions;

    HashMap<unsigned, HashSet<uint16_t, DefaultHash<uint16_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint16_t>>, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> transitionsPerTarget;

    for (const auto& transition : transitions) {
        for (unsigned targetNode : transition.value) {
            transitionsPerTarget.add(targetNode, HashSet<uint16_t, DefaultHash<uint16_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint16_t>>());
            transitionsPerTarget.find(targetNode)->value.add(transition.key);
        }
    }

    for (const auto& transitionPerTarget : transitionsPerTarget) {
        dataLogF("        %d -> %d [label=\"", sourceNode, transitionPerTarget.key);

        Vector<uint16_t> incommingCharacters;
        copyToVector(transitionPerTarget.value, incommingCharacters);
        std::sort(incommingCharacters.begin(), incommingCharacters.end());

        uint16_t rangeStart = incommingCharacters.first();
        uint16_t rangeEnd = rangeStart;
        bool first = true;
        for (unsigned sortedTransitionIndex = 1; sortedTransitionIndex < incommingCharacters.size(); ++sortedTransitionIndex) {
            uint16_t nextChar = incommingCharacters[sortedTransitionIndex];
            if (nextChar == rangeEnd+1) {
                rangeEnd = nextChar;
                continue;
            }
            printRange(first, rangeStart, rangeEnd, epsilonTransitionCharacter);
            rangeStart = rangeEnd = nextChar;
            first = false;
        }
        printRange(first, rangeStart, rangeEnd, epsilonTransitionCharacter);

        dataLogF("\"];\n");
    }

    for (unsigned targetOnAnyCharacter : node.transitionsOnAnyCharacter)
        dataLogF("        %d -> %d [label=\"[any input]\"];\n", sourceNode, targetOnAnyCharacter);
}
Example #19
0
static inline PassRefPtr<StringImpl> joinStrings(const Vector<String>& strings, const String& separator, unsigned outputLength)
{
    ASSERT(outputLength);

    CharacterType* data;
    RefPtr<StringImpl> outputStringImpl = StringImpl::tryCreateUninitialized(outputLength, data);
    if (!outputStringImpl)
        return PassRefPtr<StringImpl>();

    const String firstString = strings.first();
    appendStringToData(data, firstString);

    for (size_t i = 1; i < strings.size(); ++i) {
        appendStringToData(data, separator);
        appendStringToData(data, strings[i]);
    }

    ASSERT(data == (outputStringImpl->getCharacters<CharacterType>() + outputStringImpl->length()));
    return outputStringImpl.release();
}
Ref<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* exec, JSC::Exception* exception, size_t maxStackSize)
{
    Vector<ScriptCallFrame> frames;
    auto& stackTrace = exception->stack();
    VM& vm = exec->vm();
    for (size_t i = 0; i < stackTrace.size() && i < maxStackSize; i++) {
        unsigned line;
        unsigned column;
        stackTrace[i].computeLineAndColumn(line, column);
        String functionName = stackTrace[i].functionName(vm);
        frames.append(ScriptCallFrame(functionName, stackTrace[i].sourceURL(), static_cast<SourceID>(stackTrace[i].sourceID()), line, column));
    }

    // Fallback to getting at least the line and sourceURL from the exception object if it has values and the exceptionStack doesn't.
    if (exception->value().isObject()) {
        JSObject* exceptionObject = exception->value().toObject(exec);
        ASSERT(exceptionObject);
        int lineNumber;
        int columnNumber;
        String exceptionSourceURL;
        if (!frames.size()) {
            if (extractSourceInformationFromException(exec, exceptionObject, &lineNumber, &columnNumber, &exceptionSourceURL))
                frames.append(ScriptCallFrame(String(), exceptionSourceURL, noSourceID, lineNumber, columnNumber));
        } else {
            // FIXME: The typical stack trace will have a native frame at the top, and consumers of
            // this code already know this (see JSDOMExceptionHandling.cpp's reportException, for
            // example - it uses firstNonNativeCallFrame). This looks like it splats something else
            // over it. That something else is probably already at stackTrace[1].
            // https://bugs.webkit.org/show_bug.cgi?id=176663
            if (!stackTrace[0].hasLineAndColumnInfo() || stackTrace[0].sourceURL().isEmpty()) {
                const ScriptCallFrame& firstCallFrame = frames.first();
                if (extractSourceInformationFromException(exec, exceptionObject, &lineNumber, &columnNumber, &exceptionSourceURL))
                    frames[0] = ScriptCallFrame(firstCallFrame.functionName(), exceptionSourceURL, stackTrace[0].sourceID(), lineNumber, columnNumber);
            }
        }
    }

    return ScriptCallStack::create(frames);
}
Example #21
0
bool SVGFontData::fillBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
{
    bool haveGlyphs = false;
    Vector<SVGGlyph> glyphs;
    for (unsigned i = 0; i < length; ++i) {
        String lookupString(buffer + i, 1);
        fontElement->collectGlyphsForString(lookupString, glyphs);
        if (glyphs.isEmpty()) {
            pageToFill->setGlyphDataForIndex(offset + i, 0, 0);
            continue;
        }

        // Associate entry in glyph page with first valid SVGGlyph.
        // If there are multiple valid ones, just take the first one. WidthIterator will take
        // care of matching to the correct glyph, if multiple ones are available, as that's
        // only possible within the context of a string (eg. arabic form matching).
        haveGlyphs = true;
        pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
        glyphs.clear();
    }

    return haveGlyphs;
}
Example #22
0
static void dumpVariable(  Stream& stream,
                           Dictionary::Entry* entry,
                           const char* inClass = NULL )
{
   // Skip variables defined in script.
   
   if( entry->type < 0 )
      return;
         
   // Skip internals... don't export them.
   if (  entry->mUsage &&
         ( dStrstr( entry->mUsage, "@hide" ) || dStrstr( entry->mUsage, "@internal" ) ) )
      return;

   // Split up qualified name.

   Vector< String > nameComponents;
   String( entry->name ).split( "::", nameComponents );
   if( !nameComponents.size() ) // Safety check.
      return;
      
   // Match filter.
   
   if( inClass )
   {
      // Make sure first qualifier in name components is a
      // namespace qualifier matching the given class name.
      
      if( nameComponents.size() <= 1 || dStricmp( nameComponents.first().c_str() + 1, inClass ) != 0 ) // Skip '$'.
         return;
   }
   else
   {
      // Make sure, this is *not* in a class namespace.
      
      if( nameComponents.size() > 1 && Con::lookupNamespace( nameComponents.first().c_str() + 1 )->mClassRep )
         return;
   }
            
   // Skip variables for which we can't decipher their type.

   ConsoleBaseType* type = ConsoleBaseType::getType( entry->type );
   if( !type )
   {
      Con::errorf( "Can't find type for variable '%s'", entry->name );
      return;
   }

   // Write doc comment.
   
   stream.writeText( "/*!\r\n" );
   
   if( !inClass )
   {
      stream.writeText( "@var " );
      stream.writeText( type->getTypeClassName() );
      stream.writeText( " " );
      stream.writeText( entry->name );
      stream.writeText( ";\r\n" );
   }
   
   dumpDoc( stream, entry->mUsage );
   
   stream.writeText( "*/\r\n" );
   
   // Write definition.
   
   const U32 numNameComponents = nameComponents.size();
   if( !inClass && numNameComponents > 1 )
      for( U32 i = 0; i < ( numNameComponents - 1 ); ++ i )
      {
         stream.writeText( "namespace " );
         stream.writeText( nameComponents[ i ] );
         stream.writeText( " { " );
      }
   
   if( inClass )
      stream.writeText( "static " );
      
   if( entry->mIsConstant )
      stream.writeText( "const " );
      
   stream.writeText( type->getTypeClassName() );
   stream.writeText( " " );
   stream.writeText( nameComponents.last() );
   stream.writeText( ";" );
   
   if( !inClass && numNameComponents > 1 )
      for( U32 i = 0; i < ( numNameComponents - 1 ); ++ i )
         stream.writeText( " } " );
         
   stream.writeText( "\r\n" );
}
Example #23
0
bool decodeResourceError(ArgumentDecoder* decoder, WebCore::ResourceError& resourceError)
{
    String domain;
    int errorCode;
    String failingURL;
    String localizedDescription;
    if (!decoder->decode(CoreIPC::Out(domain, errorCode, failingURL, localizedDescription)))
        return false;

#if USE(CFNETWORK)
    WebKit::PlatformCertificateInfo certificate;
    if (!decoder->decode(certificate))
        return false;
    
    const Vector<PCCERT_CONTEXT> certificateChain = certificate.certificateChain();
    if (!certificateChain.isEmpty()) {
        ASSERT(certificateChain.size() == 1);
        resourceError = WebCore::ResourceError(domain, errorCode, failingURL, localizedDescription, WebCore::copyCertificateToData(certificateChain.first()).get());
        return true;
    }
#endif

    resourceError = WebCore::ResourceError(domain, errorCode, failingURL, localizedDescription);
    return true;
}
void BreakBlockquoteCommand::doApply()
{
    if (endingSelection().isNone())
        return;

    // Delete the current selection.
    if (endingSelection().isRange())
        deleteSelection(false, false);

    // This is a scenario that should never happen, but we want to
    // make sure we don't dereference a null pointer below.

    ASSERT(!endingSelection().isNone());

    if (endingSelection().isNone())
        return;

    VisiblePosition visiblePos = endingSelection().visibleStart();

    // pos is a position equivalent to the caret.  We use downstream() so that pos will
    // be in the first node that we need to move (there are a few exceptions to this, see below).
    Position pos = endingSelection().start().downstream();

    // Find the top-most blockquote from the start.
    Node* topBlockquote = highestEnclosingNodeOfType(pos, isMailBlockquote);
    if (!topBlockquote || !topBlockquote->parentNode() || !topBlockquote->isElementNode())
        return;

    RefPtr<Element> breakNode = createBreakElement(document());

    bool isLastVisPosInNode = isLastVisiblePositionInNode(visiblePos, topBlockquote);

    // If the position is at the beginning of the top quoted content, we don't need to break the quote.
    // Instead, insert the break before the blockquote, unless the position is as the end of the the quoted content.
    if (isFirstVisiblePositionInNode(visiblePos, topBlockquote) && !isLastVisPosInNode) {
        insertNodeBefore(breakNode.get(), topBlockquote);
        setEndingSelection(VisibleSelection(positionBeforeNode(breakNode.get()), DOWNSTREAM, endingSelection().isDirectional()));
        rebalanceWhitespace();
        return;
    }

    // Insert a break after the top blockquote.
    insertNodeAfter(breakNode.get(), topBlockquote);

    // If we're inserting the break at the end of the quoted content, we don't need to break the quote.
    if (isLastVisPosInNode) {
        setEndingSelection(VisibleSelection(positionBeforeNode(breakNode.get()), DOWNSTREAM, endingSelection().isDirectional()));
        rebalanceWhitespace();
        return;
    }

    // Don't move a line break just after the caret.  Doing so would create an extra, empty paragraph
    // in the new blockquote.
    if (lineBreakExistsAtVisiblePosition(visiblePos))
        pos = pos.next();

    // Adjust the position so we don't split at the beginning of a quote.
    while (isFirstVisiblePositionInNode(VisiblePosition(pos), enclosingNodeOfType(pos, isMailBlockquote)))
        pos = pos.previous();

    // startNode is the first node that we need to move to the new blockquote.
    Node* startNode = pos.deprecatedNode();

    // Split at pos if in the middle of a text node.
    if (startNode->isTextNode()) {
        Text* textNode = toText(startNode);
        if ((unsigned)pos.deprecatedEditingOffset() >= textNode->length()) {
            startNode = NodeTraversal::next(startNode);
            ASSERT(startNode);
        } else if (pos.deprecatedEditingOffset() > 0)
            splitTextNode(textNode, pos.deprecatedEditingOffset());
    } else if (pos.deprecatedEditingOffset() > 0) {
        Node* childAtOffset = startNode->childNode(pos.deprecatedEditingOffset());
        startNode = childAtOffset ? childAtOffset : NodeTraversal::next(startNode);
        ASSERT(startNode);
    }

    // If there's nothing inside topBlockquote to move, we're finished.
    if (!startNode->isDescendantOf(topBlockquote)) {
        setEndingSelection(VisibleSelection(VisiblePosition(firstPositionInOrBeforeNode(startNode)), endingSelection().isDirectional()));
        return;
    }

    // Build up list of ancestors in between the start node and the top blockquote.
    Vector<RefPtr<Element> > ancestors;
    for (Element* node = startNode->parentElement(); node && node != topBlockquote; node = node->parentElement())
        ancestors.append(node);

    // Insert a clone of the top blockquote after the break.
    RefPtr<Element> clonedBlockquote = toElement(topBlockquote)->cloneElementWithoutChildren();
    insertNodeAfter(clonedBlockquote.get(), breakNode.get());

    // Clone startNode's ancestors into the cloned blockquote.
    // On exiting this loop, clonedAncestor is the lowest ancestor
    // that was cloned (i.e. the clone of either ancestors.last()
    // or clonedBlockquote if ancestors is empty).
    RefPtr<Element> clonedAncestor = clonedBlockquote;
    for (size_t i = ancestors.size(); i != 0; --i) {
        RefPtr<Element> clonedChild = ancestors[i - 1]->cloneElementWithoutChildren();
        // Preserve list item numbering in cloned lists.
        if (clonedChild->isElementNode() && clonedChild->hasTagName(olTag)) {
            Node* listChildNode = i > 1 ? ancestors[i - 2].get() : startNode;
            // The first child of the cloned list might not be a list item element,
            // find the first one so that we know where to start numbering.
            while (listChildNode && !listChildNode->hasTagName(liTag))
                listChildNode = listChildNode->nextSibling();
            if (listChildNode && listChildNode->renderer() && listChildNode->renderer()->isListItem())
                setNodeAttribute(clonedChild, startAttr, String::number(toRenderListItem(listChildNode->renderer())->value()));
        }

        appendNode(clonedChild.get(), clonedAncestor.get());
        clonedAncestor = clonedChild;
    }

    moveRemainingSiblingsToNewParent(startNode, 0, clonedAncestor);

    if (!ancestors.isEmpty()) {
        // Split the tree up the ancestor chain until the topBlockquote
        // Throughout this loop, clonedParent is the clone of ancestor's parent.
        // This is so we can clone ancestor's siblings and place the clones
        // into the clone corresponding to the ancestor's parent.
        RefPtr<Element> ancestor;
        RefPtr<Element> clonedParent;
        for (ancestor = ancestors.first(), clonedParent = clonedAncestor->parentElement();
             ancestor && ancestor != topBlockquote;
             ancestor = ancestor->parentElement(), clonedParent = clonedParent->parentElement())
            moveRemainingSiblingsToNewParent(ancestor->nextSibling(), 0, clonedParent);

        // If the startNode's original parent is now empty, remove it
        Node* originalParent = ancestors.first().get();
        if (!originalParent->hasChildNodes())
            removeNode(originalParent);
    }

    // Make sure the cloned block quote renders.
    addBlockPlaceholderIfNeeded(clonedBlockquote.get());

    // Put the selection right before the break.
    setEndingSelection(VisibleSelection(positionBeforeNode(breakNode.get()), DOWNSTREAM, endingSelection().isDirectional()));
    rebalanceWhitespace();
}
Example #25
0
static Vector<SVGGlyphIdentifier::ArabicForm> charactersWithArabicForm(const String& input, bool rtl)
{
    Vector<SVGGlyphIdentifier::ArabicForm> forms;
    unsigned length = input.length();

    bool containsArabic = false;
    for (unsigned i = 0; i < length; ++i) {
        if (isArabicChar(input[i])) {
            containsArabic = true;
            break;
        }
    }

    if (!containsArabic)
        return forms;

    bool lastCharShapesRight = false;

    // Start identifying arabic forms
    if (rtl) {
        for (int i = length - 1; i >= 0; --i)
            forms.prepend(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.first()));
    } else {
        for (unsigned i = 0; i < length; ++i)
            forms.append(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.last()));
    }

    return forms;
}
inline static bool ancestorsCrossShadowBoundaries(const Vector<EventContext>& ancestors)
{
    return ancestors.isEmpty() || ancestors.first().node() == ancestors.last().node();
}
void TSLastDetail::_update()
{
   // We're gonna render... make sure we can.
   bool sceneBegun = GFX->canCurrentlyRender();
   if ( !sceneBegun )
      GFX->beginScene();

   _validateDim();

   Vector<GBitmap*> bitmaps;
   Vector<GBitmap*> normalmaps;

   // We need to create our own instance to render with.
   TSShapeInstance *shape = new TSShapeInstance( mShape, true );

   // Animate the shape once.
   shape->animate( mDl );

   // So we don't have to change it everywhere.
   const GFXFormat format = GFXFormatR8G8B8A8;  

   S32 imposterCount = ( ((2*mNumPolarSteps) + 1 ) * mNumEquatorSteps ) + ( mIncludePoles ? 2 : 0 );

   // Figure out the optimal texture size.
   Point2I texSize( smMaxTexSize, smMaxTexSize );
   while ( true )
   {
      Point2I halfSize( texSize.x / 2, texSize.y / 2 );
      U32 count = ( halfSize.x / mDim ) * ( halfSize.y / mDim );
      if ( count < imposterCount )
      {
         // Try half of the height.
         count = ( texSize.x / mDim ) * ( halfSize.y / mDim );
         if ( count >= imposterCount )
            texSize.y = halfSize.y;
         break;
      }

      texSize = halfSize;
   }

   GBitmap *imposter = NULL;
   GBitmap *normalmap = NULL;
   GBitmap destBmp( texSize.x, texSize.y, true, format );
   GBitmap destNormal( texSize.x, texSize.y, true, format );

   U32 mipLevels = destBmp.getNumMipLevels();

   ImposterCapture *imposterCap = new ImposterCapture();

   F32 equatorStepSize = M_2PI_F / (F32)mNumEquatorSteps;

   static const MatrixF topXfm( EulerF( -M_PI_F / 2.0f, 0, 0 ) );
   static const MatrixF bottomXfm( EulerF( M_PI_F / 2.0f, 0, 0 ) );

   MatrixF angMat;

   F32 polarStepSize = 0.0f;
   if ( mNumPolarSteps > 0 )
      polarStepSize = -( 0.5f * M_PI_F - mDegToRad( mPolarAngle ) ) / (F32)mNumPolarSteps;

   PROFILE_START(TSLastDetail_snapshots);

   S32 currDim = mDim;
   for ( S32 mip = 0; mip < mipLevels; mip++ )
   {
      if ( currDim < 1 )
         currDim = 1;
      
      dMemset( destBmp.getWritableBits(mip), 0, destBmp.getWidth(mip) * destBmp.getHeight(mip) * GFXFormat_getByteSize( format ) );
      dMemset( destNormal.getWritableBits(mip), 0, destNormal.getWidth(mip) * destNormal.getHeight(mip) * GFXFormat_getByteSize( format ) );

      bitmaps.clear();
      normalmaps.clear();

      F32 rotX = 0.0f;
      if ( mNumPolarSteps > 0 )
         rotX = -( mDegToRad( mPolarAngle ) - 0.5f * M_PI_F );

      // We capture the images in a particular order which must
      // match the order expected by the imposter renderer.

      imposterCap->begin( shape, mDl, currDim, mRadius, mCenter );

      for ( U32 j=0; j < (2 * mNumPolarSteps + 1); j++ )
      {
         F32 rotZ = -M_PI_F / 2.0f;

         for ( U32 k=0; k < mNumEquatorSteps; k++ )
         {            
            angMat.mul( MatrixF( EulerF( rotX, 0, 0 ) ),
                        MatrixF( EulerF( 0, 0, rotZ ) ) );

            imposterCap->capture( angMat, &imposter, &normalmap );

            bitmaps.push_back( imposter );
            normalmaps.push_back( normalmap );

            rotZ += equatorStepSize;
         }

         rotX += polarStepSize;

         if ( mIncludePoles )
         {
            imposterCap->capture( topXfm, &imposter, &normalmap );

            bitmaps.push_back(imposter);
            normalmaps.push_back( normalmap );

            imposterCap->capture( bottomXfm, &imposter, &normalmap );

            bitmaps.push_back( imposter );
            normalmaps.push_back( normalmap );
         }         
      }

      imposterCap->end();

      Point2I texSize( destBmp.getWidth(mip), destBmp.getHeight(mip) );

      // Ok... pack in bitmaps till we run out.
      for ( S32 y=0; y+currDim <= texSize.y; )
      {
         for ( S32 x=0; x+currDim <= texSize.x; )
         {
            // Copy the next bitmap to the dest texture.
            GBitmap* bmp = bitmaps.first();
            bitmaps.pop_front();
            destBmp.copyRect( bmp, RectI( 0, 0, currDim, currDim ), Point2I( x, y ), 0, mip );
            delete bmp;

            // Copy the next normal to the dest texture.
            GBitmap* normalmap = normalmaps.first();
            normalmaps.pop_front();
            destNormal.copyRect( normalmap, RectI( 0, 0, currDim, currDim ), Point2I( x, y ), 0, mip );
            delete normalmap;

            // Did we finish?
            if ( bitmaps.empty() )
               break;

            x += currDim;
         }

         // Did we finish?
         if ( bitmaps.empty() )
            break;

         y += currDim;
      }

      // Next mip...
      currDim /= 2;
   }

   PROFILE_END(); // TSLastDetail_snapshots

   delete imposterCap;
   delete shape;   
   
   
   // Should we dump the images?
   if ( Con::getBoolVariable( "$TSLastDetail::dumpImposters", false ) )
   {
      String imposterPath = mCachePath + ".imposter.png";
      String normalsPath = mCachePath + ".imposter_normals.png";

      FileStream stream;
      if ( stream.open( imposterPath, Torque::FS::File::Write  ) )
         destBmp.writeBitmap( "png", stream );
      stream.close();

      if ( stream.open( normalsPath, Torque::FS::File::Write ) )
         destNormal.writeBitmap( "png", stream );
      stream.close();
   }

   // DEBUG: Some code to force usage of a test image.
   //GBitmap* tempMap = GBitmap::load( "./forest/data/test1234.png" );
   //tempMap->extrudeMipLevels();
   //mTexture.set( tempMap, &GFXDefaultStaticDiffuseProfile, false );
   //delete tempMap;

   DDSFile *ddsDest = DDSFile::createDDSFileFromGBitmap( &destBmp );
   DDSUtil::squishDDS( ddsDest, GFXFormatDXT3 );

   DDSFile *ddsNormals = DDSFile::createDDSFileFromGBitmap( &destNormal );
   DDSUtil::squishDDS( ddsNormals, GFXFormatDXT5 );

   // Finally save the imposters to disk.
   FileStream fs;
   if ( fs.open( _getDiffuseMapPath(), Torque::FS::File::Write ) )
   {
      ddsDest->write( fs );
      fs.close();
   }
   if ( fs.open( _getNormalMapPath(), Torque::FS::File::Write ) )
   {
      ddsNormals->write( fs );
      fs.close();
   }

   delete ddsDest;
   delete ddsNormals;

   // If we did a begin then end it now.
   if ( !sceneBegun )
      GFX->endScene();
}
bool ArgumentCoder<ResourceError>::decode(ArgumentDecoder* decoder, ResourceError& resourceError)
{
    String domain;
    if (!decoder->decode(domain))
        return false;

    int errorCode;
    if (!decoder->decode(errorCode))
        return false;

    String failingURL;
    if (!decoder->decode(failingURL))
        return false;

    String localizedDescription;
    if (!decoder->decode(localizedDescription))
        return false;

#if USE(CFNETWORK)
    PlatformCertificateInfo certificate;
    if (!decoder->decode(certificate))
        return false;
    
    const Vector<PCCERT_CONTEXT> certificateChain = certificate.certificateChain();
    if (!certificateChain.isEmpty()) {
        ASSERT(certificateChain.size() == 1);
        resourceError = ResourceError(domain, errorCode, failingURL, localizedDescription, copyCertificateToData(certificateChain.first()).get());
        return true;
    }
#endif

    resourceError = ResourceError(domain, errorCode, failingURL, localizedDescription);
    return true;
}
Example #29
0
void PluginDatabase::loadPersistentMetadataCache()
{
    if (!isPersistentMetadataCacheEnabled() || persistentMetadataCachePath().isEmpty())
        return;

    PlatformFileHandle file;
    String absoluteCachePath = pathByAppendingComponent(persistentMetadataCachePath(), persistentPluginMetadataCacheFilename);
    file = openFile(absoluteCachePath, OpenForRead);

    if (!isHandleValid(file))
        return;

    // Mark cache as loaded regardless of success or failure. If
    // there's error in the cache, we won't try to load it anymore.
    m_persistentMetadataCacheIsLoaded = true;

    Vector<char> fileContents;
    fillBufferWithContentsOfFile(file, fileContents);
    closeFile(file);

    if (fileContents.size() < 2 || fileContents.first() != schemaVersion || fileContents.last() != '\0') {
        LOG_ERROR("Unable to read plugin metadata cache: corrupt schema");
        deleteFile(absoluteCachePath);
        return;
    }

    char* bufferPos = fileContents.data() + 1;
    char* end = fileContents.data() + fileContents.size();

    PluginSet cachedPlugins;
    HashMap<String, time_t> cachedPluginPathsWithTimes;
    HashMap<String, RefPtr<PluginPackage> > cachedPluginsByPath;

    while (bufferPos < end) {
        String path;
        time_t lastModified;
        String name;
        String desc;
        String mimeDesc;
        if (!(readUTF8String(path, bufferPos, end)
              && readTime(lastModified, bufferPos, end)
              && readUTF8String(name, bufferPos, end)
              && readUTF8String(desc, bufferPos, end)
              && readUTF8String(mimeDesc, bufferPos, end))) {
            LOG_ERROR("Unable to read plugin metadata cache: corrupt data");
            deleteFile(absoluteCachePath);
            return;
        }

        // Skip metadata that points to plugins from directories that
        // are not part of plugin directory list anymore.
        String pluginDirectoryName = directoryName(path);
        if (m_pluginDirectories.find(pluginDirectoryName) == WTF::notFound)
            continue;

        RefPtr<PluginPackage> package = PluginPackage::createPackageFromCache(path, lastModified, name, desc, mimeDesc);

        if (package && cachedPlugins.add(package).isNewEntry) {
            cachedPluginPathsWithTimes.add(package->path(), package->lastModified());
            cachedPluginsByPath.add(package->path(), package);
        }
    }

    m_plugins.swap(cachedPlugins);
    m_pluginsByPath.swap(cachedPluginsByPath);
    m_pluginPathsWithTimes.swap(cachedPluginPathsWithTimes);
}
void InsertParagraphSeparatorCommand::doApply()
{
    bool splitText = false;
    if (endingSelection().isNone())
        return;
    
    Position insertionPosition = endingSelection().start();
        
    EAffinity affinity = endingSelection().affinity();
        
    // Delete the current selection.
    if (endingSelection().isRange()) {
        calculateStyleBeforeInsertion(insertionPosition);
        deleteSelection(false, true);
        insertionPosition = endingSelection().start();
        affinity = endingSelection().affinity();
    }
    
    // FIXME: The rangeCompliantEquivalent conversion needs to be moved into enclosingBlock.
    Node* startBlockNode = enclosingBlock(rangeCompliantEquivalent(insertionPosition).node());
    Position canonicalPos = VisiblePosition(insertionPosition).deepEquivalent();
    Element* startBlock = static_cast<Element*>(startBlockNode);
    if (!startBlockNode
            || !startBlockNode->isElementNode()
            || !startBlock->parentNode()
            || isTableCell(startBlock)
            || startBlock->hasTagName(formTag)
            || (canonicalPos.node()->renderer() && canonicalPos.node()->renderer()->isTable())
            || canonicalPos.node()->hasTagName(hrTag)) {
        applyCommandToComposite(InsertLineBreakCommand::create(document()));
        return;
    }
    
    // Use the leftmost candidate.
    insertionPosition = insertionPosition.upstream();
    if (!insertionPosition.isCandidate())
        insertionPosition = insertionPosition.downstream();

    // Adjust the insertion position after the delete
    insertionPosition = positionAvoidingSpecialElementBoundary(insertionPosition);
    VisiblePosition visiblePos(insertionPosition, affinity);
    calculateStyleBeforeInsertion(insertionPosition);

    //---------------------------------------------------------------------
    // Handle special case of typing return on an empty list item
    if (breakOutOfEmptyListItem())
        return;

    //---------------------------------------------------------------------
    // Prepare for more general cases.

    bool isFirstInBlock = isStartOfBlock(visiblePos);
    bool isLastInBlock = isEndOfBlock(visiblePos);
    bool nestNewBlock = false;

    // Create block to be inserted.
    RefPtr<Element> blockToInsert;
    if (startBlock == startBlock->rootEditableElement()) {
        blockToInsert = createDefaultParagraphElement(document());
        nestNewBlock = true;
    } else if (shouldUseDefaultParagraphElement(startBlock)) 
        blockToInsert = createDefaultParagraphElement(document());
    else
        blockToInsert = startBlock->cloneElementWithoutChildren();

    //---------------------------------------------------------------------
    // Handle case when position is in the last visible position in its block,
    // including when the block is empty. 
    if (isLastInBlock) {
        bool shouldApplyStyleAfterInsertion = true;
        if (nestNewBlock) {
            if (isFirstInBlock && !lineBreakExistsAtVisiblePosition(visiblePos)) {
                // The block is empty.  Create an empty block to
                // represent the paragraph that we're leaving.
                RefPtr<Element> extraBlock = createDefaultParagraphElement(document());
                appendNode(extraBlock, startBlock);
                appendBlockPlaceholder(extraBlock);
            }
            appendNode(blockToInsert, startBlock);
        } else {
            // We can get here if we pasted a copied portion of a blockquote with a newline at the end and are trying to paste it
            // into an unquoted area. We then don't want the newline within the blockquote or else it will also be quoted.
            if (Node* highestBlockquote = highestEnclosingNodeOfType(canonicalPos, &isMailBlockquote)) {
                startBlock = static_cast<Element*>(highestBlockquote);
                // When inserting the newline after the blockquote, we don't want to apply the original style after the insertion
                shouldApplyStyleAfterInsertion = false;
            }
            insertNodeAfter(blockToInsert, startBlock);
        }

        appendBlockPlaceholder(blockToInsert);
        setEndingSelection(VisibleSelection(Position(blockToInsert.get(), 0), DOWNSTREAM));
        if (shouldApplyStyleAfterInsertion)
            applyStyleAfterInsertion(startBlock);
        return;
    }

    //---------------------------------------------------------------------
    // Handle case when position is in the first visible position in its block, and
    // similar case where previous position is in another, presumeably nested, block.
    if (isFirstInBlock || !inSameBlock(visiblePos, visiblePos.previous())) {
        Node *refNode;
        if (isFirstInBlock && !nestNewBlock)
            refNode = startBlock;
        else if (insertionPosition.node() == startBlock && nestNewBlock) {
            refNode = startBlock->childNode(insertionPosition.deprecatedEditingOffset());
            ASSERT(refNode); // must be true or we'd be in the end of block case
        } else
            refNode = insertionPosition.node();

        // find ending selection position easily before inserting the paragraph
        insertionPosition = insertionPosition.downstream();
        
        insertNodeBefore(blockToInsert, refNode);
        appendBlockPlaceholder(blockToInsert.get());
        setEndingSelection(VisibleSelection(Position(blockToInsert.get(), 0), DOWNSTREAM));
        applyStyleAfterInsertion(startBlock);
        setEndingSelection(VisibleSelection(insertionPosition, DOWNSTREAM));
        return;
    }

    //---------------------------------------------------------------------
    // Handle the (more complicated) general case,

    // All of the content in the current block after visiblePos is
    // about to be wrapped in a new paragraph element.  Add a br before 
    // it if visiblePos is at the start of a paragraph so that the 
    // content will move down a line.
    if (isStartOfParagraph(visiblePos)) {
        RefPtr<Element> br = createBreakElement(document());
        insertNodeAt(br.get(), insertionPosition);
        insertionPosition = positionAfterNode(br.get());
    }
    
    // Move downstream. Typing style code will take care of carrying along the 
    // style of the upstream position.
    insertionPosition = insertionPosition.downstream();

    // At this point, the insertionPosition's node could be a container, and we want to make sure we include
    // all of the correct nodes when building the ancestor list.  So this needs to be the deepest representation of the position
    // before we walk the DOM tree.
    insertionPosition = VisiblePosition(insertionPosition).deepEquivalent();

    // Build up list of ancestors in between the start node and the start block.
    Vector<Element*> ancestors;
    if (insertionPosition.node() != startBlock) {
        for (Element* n = insertionPosition.node()->parentElement(); n && n != startBlock; n = n->parentElement())
            ancestors.append(n);
    }

    // Make sure we do not cause a rendered space to become unrendered.
    // FIXME: We need the affinity for pos, but pos.downstream() does not give it
    Position leadingWhitespace = insertionPosition.leadingWhitespacePosition(VP_DEFAULT_AFFINITY);
    // FIXME: leadingWhitespacePosition is returning the position before preserved newlines for positions
    // after the preserved newline, causing the newline to be turned into a nbsp.
    if (leadingWhitespace.isNotNull()) {
        Text* textNode = static_cast<Text*>(leadingWhitespace.node());
        ASSERT(!textNode->renderer() || textNode->renderer()->style()->collapseWhiteSpace());
        replaceTextInNode(textNode, leadingWhitespace.deprecatedEditingOffset(), 1, nonBreakingSpaceString());
    }
    
    // Split at pos if in the middle of a text node.
    if (insertionPosition.node()->isTextNode()) {
        Text* textNode = static_cast<Text*>(insertionPosition.node());
        bool atEnd = (unsigned)insertionPosition.deprecatedEditingOffset() >= textNode->length();
        if (insertionPosition.deprecatedEditingOffset() > 0 && !atEnd) {
            splitTextNode(textNode, insertionPosition.deprecatedEditingOffset());
            insertionPosition.moveToOffset(0);
            visiblePos = VisiblePosition(insertionPosition);
            splitText = true;
        }
    }

    // Put the added block in the tree.
    if (nestNewBlock)
        appendNode(blockToInsert.get(), startBlock);
    else
        insertNodeAfter(blockToInsert.get(), startBlock);

    updateLayout();
    
    // Make clones of ancestors in between the start node and the start block.
    RefPtr<Element> parent = blockToInsert;
    for (size_t i = ancestors.size(); i != 0; --i) {
        RefPtr<Element> child = ancestors[i - 1]->cloneElementWithoutChildren();
        appendNode(child, parent);
        parent = child.release();
    }

    // If the paragraph separator was inserted at the end of a paragraph, an empty line must be
    // created.  All of the nodes, starting at visiblePos, are about to be added to the new paragraph 
    // element.  If the first node to be inserted won't be one that will hold an empty line open, add a br.
    if (isEndOfParagraph(visiblePos) && !lineBreakExistsAtVisiblePosition(visiblePos))
        appendNode(createBreakElement(document()).get(), blockToInsert.get());
        
    // Move the start node and the siblings of the start node.
    if (insertionPosition.node() != startBlock) {
        Node* n = insertionPosition.node();
        if (insertionPosition.deprecatedEditingOffset() >= caretMaxOffset(n))
            n = n->nextSibling();

        while (n && n != blockToInsert) {
            Node *next = n->nextSibling();
            removeNode(n);
            appendNode(n, parent.get());
            n = next;
        }
    }            

    // Move everything after the start node.
    if (!ancestors.isEmpty()) {
        Element* leftParent = ancestors.first();
        while (leftParent && leftParent != startBlock) {
            parent = parent->parentElement();
            if (!parent)
                break;
            Node* n = leftParent->nextSibling();
            while (n && n != blockToInsert) {
                Node* next = n->nextSibling();
                removeNode(n);
                appendNode(n, parent.get());
                n = next;
            }
            leftParent = leftParent->parentElement();
        }
    }

    // Handle whitespace that occurs after the split
    if (splitText) {
        updateLayout();
        insertionPosition = Position(insertionPosition.node(), 0);
        if (!insertionPosition.isRenderedCharacter()) {
            // Clear out all whitespace and insert one non-breaking space
            ASSERT(insertionPosition.node()->isTextNode());
            ASSERT(!insertionPosition.node()->renderer() || insertionPosition.node()->renderer()->style()->collapseWhiteSpace());
            deleteInsignificantTextDownstream(insertionPosition);
            insertTextIntoNode(static_cast<Text*>(insertionPosition.node()), 0, nonBreakingSpaceString());
        }
    }

    setEndingSelection(VisibleSelection(Position(blockToInsert.get(), 0), DOWNSTREAM));
    applyStyleAfterInsertion(startBlock);
}