Merge from Chromium at DEPS revision 40.0.2214.87

This commit was generated by merge_to_master.py.

Change-Id: I6a8b2e88ece9403ee841196f2f7fd91017710005
diff --git a/Source/core/css/html.css b/Source/core/css/html.css
index 00df892..05c18bd 100644
--- a/Source/core/css/html.css
+++ b/Source/core/css/html.css
@@ -397,6 +397,7 @@
 input, textarea, keygen, select, button {
     margin: 0__qem;
     font: -webkit-small-control;
+    text-rendering: auto; /* FIXME: Remove when tabs work with optimizeLegibility. */
     color: initial;
     letter-spacing: normal;
     word-spacing: normal;
diff --git a/Source/core/dom/Element.cpp b/Source/core/dom/Element.cpp
index 07c3cab..eaf16eb 100644
--- a/Source/core/dom/Element.cpp
+++ b/Source/core/dom/Element.cpp
@@ -3277,12 +3277,8 @@
         return v8::Handle<v8::Object>();
 
     V8PerContextData* perContextData = V8PerContextData::from(context);
-    if (!perContextData)
-        return wrapper;
-
-    CustomElementBinding* binding = perContextData->customElementBinding(customElementDefinition());
-
-    wrapper->SetPrototype(binding->prototype());
+    if (perContextData)
+        wrapper->SetPrototype(perContextData->customElementBinding(customElementDefinition())->prototype());
 
     return V8DOMWrapper::associateObjectWithWrapper(isolate, this, wrapperType, wrapper);
 }
diff --git a/Source/core/events/KeyboardEvent.cpp b/Source/core/events/KeyboardEvent.cpp
index 99be09c..e0d77f6 100644
--- a/Source/core/events/KeyboardEvent.cpp
+++ b/Source/core/events/KeyboardEvent.cpp
@@ -172,6 +172,14 @@
     // We match IE.
     if (!m_keyEvent)
         return 0;
+
+#if OS(ANDROID)
+    // FIXME: Check to see if this applies to other OS.
+    // If the key event belongs to IME composition then propagate to JS.
+    if (m_keyEvent->nativeVirtualKeyCode() == 0xE5) // VKEY_PROCESSKEY
+        return m_keyEvent->nativeVirtualKeyCode();
+#endif
+
     if (type() == EventTypeNames::keydown || type() == EventTypeNames::keyup)
         return windowsVirtualKeyCodeWithoutLocation(m_keyEvent->windowsVirtualKeyCode());
 
diff --git a/Source/core/rendering/RenderBlock.cpp b/Source/core/rendering/RenderBlock.cpp
index 8fbdcc8..2e101f1 100644
--- a/Source/core/rendering/RenderBlock.cpp
+++ b/Source/core/rendering/RenderBlock.cpp
@@ -4345,6 +4345,26 @@
     return !hasOverflowClip();
 }
 
+// Called when a positioned object moves but doesn't necessarily change size.  A simplified layout is attempted
+// that just updates the object's position. If the size does change, the object remains dirty.
+bool RenderBlock::tryLayoutDoingPositionedMovementOnly()
+{
+    LayoutUnit oldWidth = logicalWidth();
+    LogicalExtentComputedValues computedValues;
+    logicalExtentAfterUpdatingLogicalWidth(logicalTop(), computedValues);
+    // If we shrink to fit our width may have changed, so we still need full layout.
+    if (oldWidth != computedValues.m_extent)
+        return false;
+    setLogicalWidth(computedValues.m_extent);
+    setLogicalLeft(computedValues.m_position);
+    setMarginStart(computedValues.m_margins.m_start);
+    setMarginEnd(computedValues.m_margins.m_end);
+
+    LayoutUnit oldHeight = logicalHeight();
+    updateLogicalHeight();
+    return !hasPercentHeightDescendants() || oldHeight == logicalHeight();
+}
+
 #if ENABLE(ASSERT)
 void RenderBlock::checkPositionedObjectsNeedLayout()
 {
diff --git a/Source/core/rendering/RenderBlock.h b/Source/core/rendering/RenderBlock.h
index d4e3bdb..c5aef0e 100644
--- a/Source/core/rendering/RenderBlock.h
+++ b/Source/core/rendering/RenderBlock.h
@@ -369,7 +369,8 @@
 
     Node* nodeForHitTest() const;
 
-private:
+    bool tryLayoutDoingPositionedMovementOnly();
+
     virtual bool avoidsFloats() const override { return true; }
 
     bool hitTestColumns(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction);
diff --git a/Source/core/rendering/RenderBlockFlow.cpp b/Source/core/rendering/RenderBlockFlow.cpp
index 13bfdc8..a22f5c3 100644
--- a/Source/core/rendering/RenderBlockFlow.cpp
+++ b/Source/core/rendering/RenderBlockFlow.cpp
@@ -1887,8 +1887,9 @@
             LayoutRect borderBox = child->borderBoxRect();
             LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
 
-            borderBox = child->borderBoxAfterUpdatingLogicalWidth(newLogicalTop);
-            LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
+            LogicalExtentComputedValues computedValues;
+            child->logicalExtentAfterUpdatingLogicalWidth(newLogicalTop, computedValues);
+            LayoutUnit childLogicalWidthAtNewLogicalTopOffset = computedValues.m_extent;
 
             if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
                 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
diff --git a/Source/core/rendering/RenderBlockLineLayout.cpp b/Source/core/rendering/RenderBlockLineLayout.cpp
index 93dd3c5..91db4b5 100644
--- a/Source/core/rendering/RenderBlockLineLayout.cpp
+++ b/Source/core/rendering/RenderBlockLineLayout.cpp
@@ -1164,17 +1164,28 @@
         child->borderStart();
 }
 
-static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
+static inline void stripTrailingSpace(float& inlineMax, float& inlineMin,
+    RenderObject* trailingSpaceChild)
 {
     if (trailingSpaceChild && trailingSpaceChild->isText()) {
-        // Collapse away the trailing space at the end of a block.
+        // Collapse away the trailing space at the end of a block by finding
+        // the first white-space character and subtracting its width. Subsequent
+        // white-space characters have been collapsed into the first one (which
+        // can be either a space or a tab character).
         RenderText* text = toRenderText(trailingSpaceChild);
-        bool useComplexCodePath = !text->canUseSimpleFontCodePath();
-        const UChar space = ' ';
-        const Font& font = text->style()->font(); // FIXME: This ignores first-line.
-        TextRun run = constructTextRun(text, font, &space, 1, text->style(), LTR);
-        if (useComplexCodePath)
-            run.setUseComplexCodePath(true);
+        UChar trailingWhitespaceChar = ' ';
+        for (unsigned i = text->textLength(); i > 0; i--) {
+            UChar c = text->characterAt(i - 1);
+            if (!Character::treatAsSpace(c))
+                break;
+            trailingWhitespaceChar = c;
+        }
+
+        // FIXME: This ignores first-line.
+        const Font& font = text->style()->font();
+        TextRun run = constructTextRun(text, font, &trailingWhitespaceChar, 1,
+            text->style(), text->style()->direction());
+        run.setUseComplexCodePath(!text->canUseSimpleFontCodePath());
         float spaceWidth = font.width(run);
         inlineMax -= spaceWidth + font.fontDescription().wordSpacing();
         if (inlineMin > inlineMax)
diff --git a/Source/core/rendering/RenderBox.cpp b/Source/core/rendering/RenderBox.cpp
index e5f766d..3dbd51f 100644
--- a/Source/core/rendering/RenderBox.cpp
+++ b/Source/core/rendering/RenderBox.cpp
@@ -2456,16 +2456,9 @@
     if (logicalHeight == initialLogicalHeight)
         return true;
 
-    if (!logicalHeight.isPercent() || isOutOfFlowPositioned())
-        return false;
-
-    // Anonymous block boxes are ignored when resolving percentage values that would refer to it:
-    // the closest non-anonymous ancestor box is used instead.
-    RenderBlock* containingBlock = this->containingBlock();
-    while (containingBlock->isAnonymous())
-        containingBlock = containingBlock->containingBlock();
-
-    return containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight();
+    if (RenderBlock* cb = containingBlockForAutoHeightDetection(logicalHeight))
+        return cb->hasAutoHeightOrContainingBlockWithAutoHeight();
+    return false;
 }
 
 LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const
@@ -4448,24 +4441,28 @@
     return previousBoundsSize;
 }
 
-LayoutRect RenderBox::borderBoxAfterUpdatingLogicalWidth(const LayoutUnit& newLogicalTop)
+void RenderBox::logicalExtentAfterUpdatingLogicalWidth(const LayoutUnit& newLogicalTop, RenderBox::LogicalExtentComputedValues& computedValues)
 {
     // FIXME: None of this is right for perpendicular writing-mode children.
     LayoutUnit oldLogicalWidth = logicalWidth();
+    LayoutUnit oldLogicalLeft = logicalLeft();
     LayoutUnit oldMarginLeft = marginLeft();
     LayoutUnit oldMarginRight = marginRight();
     LayoutUnit oldLogicalTop = logicalTop();
 
     setLogicalTop(newLogicalTop);
     updateLogicalWidth();
-    LayoutRect borderBox = borderBoxRect();
+
+    computedValues.m_extent = logicalWidth();
+    computedValues.m_position = logicalLeft();
+    computedValues.m_margins.m_start = marginStart();
+    computedValues.m_margins.m_end = marginEnd();
 
     setLogicalTop(oldLogicalTop);
     setLogicalWidth(oldLogicalWidth);
+    setLogicalLeft(oldLogicalLeft);
     setMarginLeft(oldMarginLeft);
     setMarginRight(oldMarginRight);
-
-    return borderBox;
 }
 
 } // namespace blink
diff --git a/Source/core/rendering/RenderBox.h b/Source/core/rendering/RenderBox.h
index f383ed5..5ca9d92 100644
--- a/Source/core/rendering/RenderBox.h
+++ b/Source/core/rendering/RenderBox.h
@@ -494,22 +494,7 @@
     virtual void paintClippingMask(PaintInfo&, const LayoutPoint&);
     virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) override;
 
-    LayoutRect borderBoxAfterUpdatingLogicalWidth(const LayoutUnit& logicalTop);
-
-    // Called when a positioned object moves but doesn't necessarily change size.  A simplified layout is attempted
-    // that just updates the object's position. If the size does change, the object remains dirty.
-    bool tryLayoutDoingPositionedMovementOnly()
-    {
-        LayoutUnit oldWidth = width();
-        LayoutUnit newWidth = borderBoxAfterUpdatingLogicalWidth(logicalTop()).width();
-        // If we shrink to fit our width may have changed, so we still need full layout.
-        // FIXME: We check for potential change of width when deciding to set needsPositionedMovementLayout.
-        // So either that check or this one is unnecessary, probably the former. crbug.com/428050
-        if (oldWidth != newWidth)
-            return false;
-        updateLogicalHeight();
-        return true;
-    }
+    void logicalExtentAfterUpdatingLogicalWidth(const LayoutUnit& logicalTop, LogicalExtentComputedValues&);
 
     virtual PositionWithAffinity positionForPoint(const LayoutPoint&) override;
 
diff --git a/Source/core/rendering/RenderBoxModelObject.cpp b/Source/core/rendering/RenderBoxModelObject.cpp
index 69d4847..43e3b2e 100644
--- a/Source/core/rendering/RenderBoxModelObject.cpp
+++ b/Source/core/rendering/RenderBoxModelObject.cpp
@@ -155,17 +155,13 @@
     return offset;
 }
 
-bool RenderBoxModelObject::hasAutoHeightOrContainingBlockWithAutoHeight() const
+RenderBlock* RenderBoxModelObject::containingBlockForAutoHeightDetection(Length logicalHeight) const
 {
-    Length logicalHeightLength = style()->logicalHeight();
-    if (logicalHeightLength.isAuto())
-        return true;
-
     // For percentage heights: The percentage is calculated with respect to the height of the generated box's
     // containing block. If the height of the containing block is not specified explicitly (i.e., it depends
     // on content height), and this element is not absolutely positioned, the value computes to 'auto'.
-    if (!logicalHeightLength.isPercent() || isOutOfFlowPositioned() || document().inQuirksMode())
-        return false;
+    if (!logicalHeight.isPercent() || isOutOfFlowPositioned())
+        return 0;
 
     // Anonymous block boxes are ignored when resolving percentage values that would refer to it:
     // the closest non-anonymous ancestor box is used instead.
@@ -178,18 +174,32 @@
     // what the CSS spec says to do with heights. Basically we
     // don't care if the cell specified a height or not.
     if (cb->isTableCell())
-        return false;
+        return 0;
 
     // Match RenderBox::availableLogicalHeightUsing by special casing
     // the render view. The available height is taken from the frame.
     if (cb->isRenderView())
-        return false;
+        return 0;
 
     if (cb->isOutOfFlowPositioned() && !cb->style()->logicalTop().isAuto() && !cb->style()->logicalBottom().isAuto())
+        return 0;
+
+    return cb;
+}
+
+bool RenderBoxModelObject::hasAutoHeightOrContainingBlockWithAutoHeight() const
+{
+    Length logicalHeightLength = style()->logicalHeight();
+    if (logicalHeightLength.isAuto())
+        return true;
+
+    if (document().inQuirksMode())
         return false;
 
     // If the height of the containing block computes to 'auto', then it hasn't been 'specified explicitly'.
-    return cb->hasAutoHeightOrContainingBlockWithAutoHeight();
+    if (RenderBlock* cb = containingBlockForAutoHeightDetection(logicalHeightLength))
+        return cb->hasAutoHeightOrContainingBlockWithAutoHeight();
+    return false;
 }
 
 LayoutSize RenderBoxModelObject::relativePositionOffset() const
diff --git a/Source/core/rendering/RenderBoxModelObject.h b/Source/core/rendering/RenderBoxModelObject.h
index 40adffa..164c0ae 100644
--- a/Source/core/rendering/RenderBoxModelObject.h
+++ b/Source/core/rendering/RenderBoxModelObject.h
@@ -179,6 +179,7 @@
     LayoutRect localCaretRectForEmptyElement(LayoutUnit width, LayoutUnit textIndentOffset);
 
     bool hasAutoHeightOrContainingBlockWithAutoHeight() const;
+    RenderBlock* containingBlockForAutoHeightDetection(Length logicalHeight) const;
 
 public:
 
diff --git a/Source/core/rendering/RenderInline.cpp b/Source/core/rendering/RenderInline.cpp
index d156b0b..b436757 100644
--- a/Source/core/rendering/RenderInline.cpp
+++ b/Source/core/rendering/RenderInline.cpp
@@ -1019,29 +1019,42 @@
     return rect;
 }
 
+LayoutRect RenderInline::absoluteClippedOverflowRect() const
+{
+    return clippedOverflowRect(view());
+}
+
 LayoutRect RenderInline::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
 {
+    // If we don't create line boxes, we don't have any invalidations to do.
+    if (!alwaysCreateLineBoxes())
+        return LayoutRect();
+    return clippedOverflowRect(paintInvalidationContainer);
+}
+
+LayoutRect RenderInline::clippedOverflowRect(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
+{
     if ((!firstLineBoxIncludingCulling() && !continuation()) || style()->visibility() != VISIBLE)
         return LayoutRect();
 
-    LayoutRect paintInvalidationRect(linesVisualOverflowBoundingBox());
+    LayoutRect overflowRect(linesVisualOverflowBoundingBox());
 
     LayoutUnit outlineSize = style()->outlineSize();
-    paintInvalidationRect.inflate(outlineSize);
+    overflowRect.inflate(outlineSize);
 
-    mapRectToPaintInvalidationBacking(paintInvalidationContainer, paintInvalidationRect, paintInvalidationState);
+    mapRectToPaintInvalidationBacking(paintInvalidationContainer, overflowRect, paintInvalidationState);
 
     if (outlineSize) {
         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
             if (!curr->isText())
-                paintInvalidationRect.unite(curr->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineSize));
+                overflowRect.unite(curr->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineSize));
         }
 
         if (continuation() && !continuation()->isInline() && continuation()->parent())
-            paintInvalidationRect.unite(continuation()->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineSize));
+            overflowRect.unite(continuation()->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineSize));
     }
 
-    return paintInvalidationRect;
+    return overflowRect;
 }
 
 LayoutRect RenderInline::rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth, const PaintInvalidationState* paintInvalidationState) const
diff --git a/Source/core/rendering/RenderInline.h b/Source/core/rendering/RenderInline.h
index c277d9e..6c25269 100644
--- a/Source/core/rendering/RenderInline.h
+++ b/Source/core/rendering/RenderInline.h
@@ -144,10 +144,15 @@
     virtual LayoutUnit offsetWidth() const override final { return linesBoundingBox().width(); }
     virtual LayoutUnit offsetHeight() const override final { return linesBoundingBox().height(); }
 
+    virtual LayoutRect absoluteClippedOverflowRect() const override;
     virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* = 0) const override;
     virtual LayoutRect rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth, const PaintInvalidationState* = 0) const override final;
     virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, const PaintInvalidationState*) const override final;
 
+    // This method differs from clippedOverflowRectForPaintInvalidation in that it includes
+    // the rects for culled inline boxes, which aren't necessary for paint invalidation.
+    LayoutRect clippedOverflowRect(const RenderLayerModelObject*, const PaintInvalidationState* = 0) const;
+
     virtual void mapLocalToContainer(const RenderLayerModelObject* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0, const PaintInvalidationState* = 0) const override;
 
     virtual PositionWithAffinity positionForPoint(const LayoutPoint&) override final;
diff --git a/Source/core/rendering/RenderObject.h b/Source/core/rendering/RenderObject.h
index 618de57..503113d 100644
--- a/Source/core/rendering/RenderObject.h
+++ b/Source/core/rendering/RenderObject.h
@@ -864,7 +864,7 @@
 
     // Returns the rect that should have paint invalidated whenever this object changes. The rect is in the view's
     // coordinate space. This method deals with outlines and overflow.
-    LayoutRect absoluteClippedOverflowRect() const;
+    virtual LayoutRect absoluteClippedOverflowRect() const;
     IntRect pixelSnappedAbsoluteClippedOverflowRect() const;
     virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* = 0) const;
     virtual LayoutRect rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth, const PaintInvalidationState* = 0) const;
diff --git a/Source/core/rendering/RenderView.cpp b/Source/core/rendering/RenderView.cpp
index 02367e0..2067106 100644
--- a/Source/core/rendering/RenderView.cpp
+++ b/Source/core/rendering/RenderView.cpp
@@ -333,7 +333,7 @@
     LayoutRect dirtyRect = viewRect();
     if (doingFullPaintInvalidation() && !dirtyRect.isEmpty()) {
         const RenderLayerModelObject* paintInvalidationContainer = &paintInvalidationState.paintInvalidationContainer();
-        mapRectToPaintInvalidationBacking(paintInvalidationContainer, dirtyRect, &paintInvalidationState);
+        RenderLayer::mapRectToPaintInvalidationBacking(this, paintInvalidationContainer, dirtyRect, &paintInvalidationState);
         invalidatePaintUsingContainer(paintInvalidationContainer, dirtyRect, PaintInvalidationFull);
     }
     RenderBlock::invalidateTreeIfNeeded(paintInvalidationState);
diff --git a/Source/core/xml/XSLImportRule.cpp b/Source/core/xml/XSLImportRule.cpp
index b391b30..66e6178 100644
--- a/Source/core/xml/XSLImportRule.cpp
+++ b/Source/core/xml/XSLImportRule.cpp
@@ -106,7 +106,7 @@
 
     ASSERT(!m_styleSheet);
     if (SharedBuffer* data = resource->resourceBuffer())
-        setXSLStyleSheet(absHref, parentSheet->baseURL(), UTF8Encoding().decode(data->data(), data->size()));
+        setXSLStyleSheet(absHref, resource->response().url(), UTF8Encoding().decode(data->data(), data->size()));
 }
 
 void XSLImportRule::trace(Visitor* visitor)
diff --git a/Source/devtools/front_end/timeline/TracingTimelineUIUtils.js b/Source/devtools/front_end/timeline/TracingTimelineUIUtils.js
index 32736d3..1f50233 100644
--- a/Source/devtools/front_end/timeline/TracingTimelineUIUtils.js
+++ b/Source/devtools/front_end/timeline/TracingTimelineUIUtils.js
@@ -169,7 +169,7 @@
      */
     hiddenEmptyRecordsFilter: function()
     {
-        var hiddenEmptyRecords = [WebInspector.TimelineModel.RecordType.EventDispatch];
+        var hiddenEmptyRecords = [WebInspector.TimelineModel.RecordType.EventDispatch, WebInspector.TimelineModel.RecordType.UpdateCounters];
         return new WebInspector.TimelineRecordHiddenEmptyTypeFilter(hiddenEmptyRecords);
     },
 
@@ -247,6 +247,7 @@
     eventStyles[recordTypes.EmbedderCallback] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Embedder Callback"), categories["scripting"]);
     eventStyles[recordTypes.DecodeImage] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Image Decode"), categories["painting"]);
     eventStyles[recordTypes.ResizeImage] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("Image Resize"), categories["painting"]);
+    eventStyles[recordTypes.UpdateCounters] = new WebInspector.TimelineRecordStyle(WebInspector.UIString("UpdateCounters"), categories["other"]);
     WebInspector.TracingTimelineUIUtils._eventStylesMap = eventStyles;
     return eventStyles;
 }
diff --git a/Source/modules/webaudio/AudioBufferSourceNode.cpp b/Source/modules/webaudio/AudioBufferSourceNode.cpp
index 05738f9..3c57b56 100644
--- a/Source/modules/webaudio/AudioBufferSourceNode.cpp
+++ b/Source/modules/webaudio/AudioBufferSourceNode.cpp
@@ -233,7 +233,7 @@
     // If we're looping and the offset (virtualReadIndex) is past the end of the loop, wrap back to
     // the beginning of the loop. For other cases, nothing needs to be done.
     if (loop() && m_virtualReadIndex >= virtualEndFrame)
-        m_virtualReadIndex = m_loopStart * buffer()->sampleRate();
+        m_virtualReadIndex = (m_loopStart < 0) ? 0 : (m_loopStart * buffer()->sampleRate());
 
     double pitchRate = totalPitchRate();
 
@@ -250,6 +250,10 @@
     const float** sourceChannels = m_sourceChannels.get();
     float** destinationChannels = m_destinationChannels.get();
 
+    ASSERT(virtualReadIndex >= 0);
+    ASSERT(virtualDeltaFrames >= 0);
+    ASSERT(virtualEndFrame >= 0);
+
     // Optimize for the very common case of playing back with pitchRate == 1.
     // We can avoid the linear interpolation.
     if (pitchRate == 1 && virtualReadIndex == floor(virtualReadIndex)
diff --git a/Source/modules/webaudio/AudioContext.cpp b/Source/modules/webaudio/AudioContext.cpp
index ded030c..878b124 100644
--- a/Source/modules/webaudio/AudioContext.cpp
+++ b/Source/modules/webaudio/AudioContext.cpp
@@ -533,6 +533,11 @@
     return PeriodicWave::create(sampleRate(), real->view(), imag->view());
 }
 
+void AudioContext::notifyNodeStartedProcessing(AudioNode* node)
+{
+    refNode(node);
+}
+
 void AudioContext::notifyNodeFinishedProcessing(AudioNode* node)
 {
     ASSERT(isAudioThread());
diff --git a/Source/modules/webaudio/AudioContext.h b/Source/modules/webaudio/AudioContext.h
index f84804b..8243f05 100644
--- a/Source/modules/webaudio/AudioContext.h
+++ b/Source/modules/webaudio/AudioContext.h
@@ -129,7 +129,11 @@
     OscillatorNode* createOscillator();
     PeriodicWave* createPeriodicWave(DOMFloat32Array* real, DOMFloat32Array* imag, ExceptionState&);
 
-    // When a source node has no more processing to do (has finished playing), then it tells the context to dereference it.
+    // When a source node has started processing and needs to be protected,
+    // this method tells the context to protect the node.
+    void notifyNodeStartedProcessing(AudioNode*);
+    // When a source node has no more processing to do (has finished playing),
+    // this method tells the context to dereference the node.
     void notifyNodeFinishedProcessing(AudioNode*);
 
     // Called at the start of each render quantum.
diff --git a/Source/modules/webaudio/OfflineAudioDestinationNode.cpp b/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
index 11da979..66b60a9 100644
--- a/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
+++ b/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
@@ -81,12 +81,13 @@
 void OfflineAudioDestinationNode::startRendering()
 {
     ASSERT(isMainThread());
-    ASSERT(m_renderTarget.get());
-    if (!m_renderTarget.get())
+    ASSERT(m_renderTarget);
+    if (!m_renderTarget)
         return;
 
     if (!m_startedRendering) {
         m_startedRendering = true;
+        context()->notifyNodeStartedProcessing(this);
         m_renderThread = adoptPtr(blink::Platform::current()->createThread("Offline Audio Renderer"));
         m_renderThread->postTask(new Task(bind(&OfflineAudioDestinationNode::offlineRender, this)));
     }
@@ -94,9 +95,16 @@
 
 void OfflineAudioDestinationNode::offlineRender()
 {
+    offlineRenderInternal();
+    context()->notifyNodeFinishedProcessing(this);
+    context()->handlePostRenderTasks();
+}
+
+void OfflineAudioDestinationNode::offlineRenderInternal()
+{
     ASSERT(!isMainThread());
-    ASSERT(m_renderBus.get());
-    if (!m_renderBus.get())
+    ASSERT(m_renderBus);
+    if (!m_renderBus)
         return;
 
     bool isAudioContextInitialized = context()->isInitialized();
diff --git a/Source/modules/webaudio/OfflineAudioDestinationNode.h b/Source/modules/webaudio/OfflineAudioDestinationNode.h
index 05dba11..6e267f2 100644
--- a/Source/modules/webaudio/OfflineAudioDestinationNode.h
+++ b/Source/modules/webaudio/OfflineAudioDestinationNode.h
@@ -60,6 +60,12 @@
 private:
     OfflineAudioDestinationNode(AudioContext*, AudioBuffer* renderTarget);
 
+    void offlineRender();
+    void offlineRenderInternal();
+
+    // For completion callback on main thread.
+    void notifyComplete();
+
     // This AudioNode renders into this AudioBuffer.
     Member<AudioBuffer> m_renderTarget;
     // Temporary AudioBus for each render quantum.
@@ -68,10 +74,6 @@
     // Rendering thread.
     OwnPtr<WebThread> m_renderThread;
     bool m_startedRendering;
-    void offlineRender();
-
-    // For completion callback on main thread.
-    void notifyComplete();
 };
 
 } // namespace blink