<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[192610] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/192610">192610</a></dd>
<dt>Author</dt> <dd>beidson@apple.com</dd>
<dt>Date</dt> <dd>2015-11-18 20:36:00 -0800 (Wed, 18 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Modern IDB:Make in-memory Index cursors work.
https://bugs.webkit.org/show_bug.cgi?id=151278

Reviewed by Alex Christensen.

Source/WebCore:

Tests: storage/indexeddb/modern/index-cursor-1.html
       storage/indexeddb/modern/index-cursor-2.html
       storage/indexeddb/modern/index-cursor-3.html

* CMakeLists.txt:
* WebCore.xcodeproj/project.pbxproj:

* Modules/indexeddb/client/IDBIndexImpl.cpp:
(WebCore::IDBClient::IDBIndex::openCursor):
(WebCore::IDBClient::IDBIndex::openKeyCursor):

* Modules/indexeddb/server/IndexValueEntry.cpp:
(WebCore::IDBServer::IndexValueEntry::removeKey):
(WebCore::IDBServer::IndexValueEntry::Iterator::Iterator):
(WebCore::IDBServer::IndexValueEntry::Iterator::key):
(WebCore::IDBServer::IndexValueEntry::Iterator::isValid):
(WebCore::IDBServer::IndexValueEntry::Iterator::invalidate):
(WebCore::IDBServer::IndexValueEntry::Iterator::operator++):
(WebCore::IDBServer::IndexValueEntry::begin):
(WebCore::IDBServer::IndexValueEntry::reverseBegin):
(WebCore::IDBServer::IndexValueEntry::find):
(WebCore::IDBServer::IndexValueEntry::reverseFind):
* Modules/indexeddb/server/IndexValueEntry.h:
(WebCore::IDBServer::IndexValueEntry::Iterator::Iterator):
(WebCore::IDBServer::IndexValueEntry::unique):

* Modules/indexeddb/server/IndexValueStore.cpp:
(WebCore::IDBServer::IndexValueStore::removeEntriesWithValueKey):
(WebCore::IDBServer::IndexValueStore::lowestKeyWithRecordInRange):
(WebCore::IDBServer::IndexValueStore::lowestIteratorInRange):
(WebCore::IDBServer::IndexValueStore::highestReverseIteratorInRange):
(WebCore::IDBServer::IndexValueStore::find):
(WebCore::IDBServer::IndexValueStore::reverseFind):
(WebCore::IDBServer::IndexValueStore::Iterator::Iterator):
(WebCore::IDBServer::IndexValueStore::Iterator::nextIndexEntry):
(WebCore::IDBServer::IndexValueStore::Iterator::operator++):
(WebCore::IDBServer::IndexValueStore::Iterator::invalidate):
(WebCore::IDBServer::IndexValueStore::Iterator::isValid):
(WebCore::IDBServer::IndexValueStore::Iterator::key):
(WebCore::IDBServer::IndexValueStore::Iterator::primaryKey):
* Modules/indexeddb/server/IndexValueStore.h:
(WebCore::IDBServer::IndexValueStore::Iterator::Iterator):

* Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
(WebCore::IDBServer::MemoryIDBBackingStore::openCursor):

* Modules/indexeddb/server/MemoryIndex.cpp:
(WebCore::IDBServer::MemoryIndex::cursorDidBecomeClean):
(WebCore::IDBServer::MemoryIndex::cursorDidBecomeDirty):
(WebCore::IDBServer::MemoryIndex::objectStoreCleared):
(WebCore::IDBServer::MemoryIndex::notifyCursorsOfValueChange):
(WebCore::IDBServer::MemoryIndex::notifyCursorsOfAllRecordsChanged):
(WebCore::IDBServer::MemoryIndex::putIndexKey):
(WebCore::IDBServer::MemoryIndex::removeRecord):
(WebCore::IDBServer::MemoryIndex::removeEntriesWithValueKey):
(WebCore::IDBServer::MemoryIndex::maybeOpenCursor):
* Modules/indexeddb/server/MemoryIndex.h:
(WebCore::IDBServer::MemoryIndex::valueStore):
(WebCore::IDBServer::MemoryIndex::objectStore):

* Modules/indexeddb/server/MemoryIndexCursor.cpp: Added.
(WebCore::IDBServer::MemoryIndexCursor::MemoryIndexCursor):
(WebCore::IDBServer::MemoryIndexCursor::~MemoryIndexCursor):
(WebCore::IDBServer::MemoryIndexCursor::currentData):
(WebCore::IDBServer::MemoryIndexCursor::iterate):
(WebCore::IDBServer::MemoryIndexCursor::indexRecordsAllChanged):
(WebCore::IDBServer::MemoryIndexCursor::indexValueChanged):
* Modules/indexeddb/server/MemoryIndexCursor.h:

* Modules/indexeddb/server/MemoryObjectStore.cpp:
(WebCore::IDBServer::MemoryObjectStore::indexForIdentifier):
(WebCore::IDBServer::MemoryObjectStore::valueForKey):
* Modules/indexeddb/server/MemoryObjectStore.h:

* Modules/indexeddb/shared/IDBCursorInfo.cpp:
(WebCore::IDBCursorInfo::objectStoreCursor):
(WebCore::IDBCursorInfo::indexCursor):
(WebCore::IDBCursorInfo::IDBCursorInfo):
(WebCore::IDBCursorInfo::isDirectionNoDuplicate):
(WebCore::IDBCursorInfo::isolatedCopy):
* Modules/indexeddb/shared/IDBCursorInfo.h:
(WebCore::IDBCursorInfo::objectStoreIdentifier):

LayoutTests:

* storage/indexeddb/modern/cursor-1-expected.txt:
* storage/indexeddb/modern/index-cursor-1-expected.txt: Added.
* storage/indexeddb/modern/index-cursor-1.html: Added.
* storage/indexeddb/modern/index-cursor-2-expected.txt: Added.
* storage/indexeddb/modern/index-cursor-2.html: Added.
* storage/indexeddb/modern/index-cursor-3-expected.txt: Added.
* storage/indexeddb/modern/index-cursor-3.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmoderncursor1expectedtxt">trunk/LayoutTests/storage/indexeddb/modern/cursor-1-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreCMakeListstxt">trunk/Source/WebCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbclientIDBIndexImplcpp">trunk/Source/WebCore/Modules/indexeddb/client/IDBIndexImpl.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIndexValueEntrycpp">trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIndexValueEntryh">trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIndexValueStorecpp">trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverIndexValueStoreh">trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryIDBBackingStorecpp">trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryIndexcpp">trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryIndexh">trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryObjectStorecpp">trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryObjectStoreh">trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbsharedIDBCursorInfocpp">trunk/Source/WebCore/Modules/indexeddb/shared/IDBCursorInfo.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbsharedIDBCursorInfoh">trunk/Source/WebCore/Modules/indexeddb/shared/IDBCursorInfo.h</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindexcursor1expectedtxt">trunk/LayoutTests/storage/indexeddb/modern/index-cursor-1-expected.txt</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindexcursor1html">trunk/LayoutTests/storage/indexeddb/modern/index-cursor-1.html</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindexcursor2expectedtxt">trunk/LayoutTests/storage/indexeddb/modern/index-cursor-2-expected.txt</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindexcursor2html">trunk/LayoutTests/storage/indexeddb/modern/index-cursor-2.html</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindexcursor3expectedtxt">trunk/LayoutTests/storage/indexeddb/modern/index-cursor-3-expected.txt</a></li>
<li><a href="#trunkLayoutTestsstorageindexeddbmodernindexcursor3html">trunk/LayoutTests/storage/indexeddb/modern/index-cursor-3.html</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryIndexCursorcpp">trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesindexeddbserverMemoryIndexCursorh">trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/LayoutTests/ChangeLog        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2015-11-18  Brady Eidson  &lt;beidson@apple.com&gt;
+
+        Modern IDB:Make in-memory Index cursors work.
+        https://bugs.webkit.org/show_bug.cgi?id=151278
+
+        Reviewed by Alex Christensen.
+
+        * storage/indexeddb/modern/cursor-1-expected.txt:
+        * storage/indexeddb/modern/index-cursor-1-expected.txt: Added.
+        * storage/indexeddb/modern/index-cursor-1.html: Added.
+        * storage/indexeddb/modern/index-cursor-2-expected.txt: Added.
+        * storage/indexeddb/modern/index-cursor-2.html: Added.
+        * storage/indexeddb/modern/index-cursor-3-expected.txt: Added.
+        * storage/indexeddb/modern/index-cursor-3.html: Added.
+
</ins><span class="cx"> 2015-11-18  Antti Koivisto  &lt;antti@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Assertion failure in RenderTreePosition::computeNextSibling
</span></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmoderncursor1expectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/storage/indexeddb/modern/cursor-1-expected.txt (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/cursor-1-expected.txt        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/LayoutTests/storage/indexeddb/modern/cursor-1-expected.txt        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -6,72 +6,72 @@
</span><span class="cx"> Cursor source is: [object IDBObjectStore] (TestObjectStore)
</span><span class="cx"> Cursor key is: 0
</span><span class="cx"> Cursor primary key is: 0
</span><del>-Error opening cursor (expected for now)
</del><ins>+Success opening cursor
</ins><span class="cx"> Cursor is: [object IDBCursorWithValue]
</span><span class="cx"> Cursor direction is: next
</span><span class="cx"> Cursor source is: [object IDBIndex] (TestIndex1)
</span><del>-Cursor key is: null
-Cursor primary key is: null
-Error opening cursor (expected for now)
</del><ins>+Cursor key is: Hello
+Cursor primary key is: foo
+Success opening cursor
</ins><span class="cx"> Cursor is: [object IDBCursor]
</span><span class="cx"> Cursor direction is: next
</span><span class="cx"> Cursor source is: [object IDBIndex] (TestIndex1)
</span><del>-Cursor key is: null
-Cursor primary key is: null
</del><ins>+Cursor key is: Hello
+Cursor primary key is: foo
</ins><span class="cx"> Success opening cursor
</span><span class="cx"> Cursor is: [object IDBCursorWithValue]
</span><span class="cx"> Cursor direction is: nextunique
</span><span class="cx"> Cursor source is: [object IDBObjectStore] (TestObjectStore)
</span><span class="cx"> Cursor key is: 0
</span><span class="cx"> Cursor primary key is: 0
</span><del>-Error opening cursor (expected for now)
</del><ins>+Success opening cursor
</ins><span class="cx"> Cursor is: [object IDBCursorWithValue]
</span><span class="cx"> Cursor direction is: nextunique
</span><span class="cx"> Cursor source is: [object IDBIndex] (TestIndex1)
</span><del>-Cursor key is: null
-Cursor primary key is: null
-Error opening cursor (expected for now)
</del><ins>+Cursor key is: Hello
+Cursor primary key is: foo
+Success opening cursor
</ins><span class="cx"> Cursor is: [object IDBCursor]
</span><span class="cx"> Cursor direction is: nextunique
</span><span class="cx"> Cursor source is: [object IDBIndex] (TestIndex1)
</span><del>-Cursor key is: null
-Cursor primary key is: null
</del><ins>+Cursor key is: Hello
+Cursor primary key is: foo
</ins><span class="cx"> Success opening cursor
</span><span class="cx"> Cursor is: [object IDBCursorWithValue]
</span><span class="cx"> Cursor direction is: prev
</span><span class="cx"> Cursor source is: [object IDBObjectStore] (TestObjectStore)
</span><span class="cx"> Cursor key is: foo
</span><span class="cx"> Cursor primary key is: foo
</span><del>-Error opening cursor (expected for now)
</del><ins>+Success opening cursor
</ins><span class="cx"> Cursor is: [object IDBCursorWithValue]
</span><span class="cx"> Cursor direction is: prev
</span><span class="cx"> Cursor source is: [object IDBIndex] (TestIndex1)
</span><del>-Cursor key is: null
-Cursor primary key is: null
-Error opening cursor (expected for now)
</del><ins>+Cursor key is: Hello
+Cursor primary key is: foo
+Success opening cursor
</ins><span class="cx"> Cursor is: [object IDBCursor]
</span><span class="cx"> Cursor direction is: prev
</span><span class="cx"> Cursor source is: [object IDBIndex] (TestIndex1)
</span><del>-Cursor key is: null
-Cursor primary key is: null
</del><ins>+Cursor key is: Hello
+Cursor primary key is: foo
</ins><span class="cx"> Success opening cursor
</span><span class="cx"> Cursor is: [object IDBCursorWithValue]
</span><span class="cx"> Cursor direction is: prevunique
</span><span class="cx"> Cursor source is: [object IDBObjectStore] (TestObjectStore)
</span><span class="cx"> Cursor key is: foo
</span><span class="cx"> Cursor primary key is: foo
</span><del>-Error opening cursor (expected for now)
</del><ins>+Success opening cursor
</ins><span class="cx"> Cursor is: [object IDBCursorWithValue]
</span><span class="cx"> Cursor direction is: prevunique
</span><span class="cx"> Cursor source is: [object IDBIndex] (TestIndex1)
</span><del>-Cursor key is: null
-Cursor primary key is: null
-Error opening cursor (expected for now)
</del><ins>+Cursor key is: Hello
+Cursor primary key is: foo
+Success opening cursor
</ins><span class="cx"> Cursor is: [object IDBCursor]
</span><span class="cx"> Cursor direction is: prevunique
</span><span class="cx"> Cursor source is: [object IDBIndex] (TestIndex1)
</span><del>-Cursor key is: null
-Cursor primary key is: null
</del><ins>+Cursor key is: Hello
+Cursor primary key is: foo
</ins><span class="cx"> Initial upgrade versionchange transaction complete
</span><span class="cx"> Done
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindexcursor1expectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/index-cursor-1-expected.txt (0 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-cursor-1-expected.txt                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-cursor-1-expected.txt        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -0,0 +1,454 @@
</span><ins>+This tests cursors that iterate over entire indexes.
+Initial upgrade needed: Old version - 0 New version - 1
+
+Starting a new cursor: testCursorDirection(index1, 'next')
+TestIndex1 count is: 12
+TestIndex2 count is: 12
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 2
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 3
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 5
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 8
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 10
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 11
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 12
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection(index2, 'next')
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: a
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: a
+Cursor primary key is: 2
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: a
+Cursor primary key is: 3
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: b
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: b
+Cursor primary key is: 5
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: b
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: c
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: c
+Cursor primary key is: 8
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: c
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: d
+Cursor primary key is: 10
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: d
+Cursor primary key is: 11
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: d
+Cursor primary key is: 12
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex2
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection(index1, 'nextunique')
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 10
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection(index2, 'nextunique')
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex2
+Cursor key is: a
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex2
+Cursor key is: b
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex2
+Cursor key is: c
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex2
+Cursor key is: d
+Cursor primary key is: 10
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex2
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection(index1, 'prev')
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 12
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 11
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 10
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 8
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 5
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 3
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 2
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection(index2, 'prev')
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: d
+Cursor primary key is: 12
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: d
+Cursor primary key is: 11
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: d
+Cursor primary key is: 10
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: c
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: c
+Cursor primary key is: 8
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: c
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: b
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: b
+Cursor primary key is: 5
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: b
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: a
+Cursor primary key is: 3
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: a
+Cursor primary key is: 2
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: a
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex2
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection(index1, 'prevunique')
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 12
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 3
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection(index2, 'prevunique')
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex2
+Cursor key is: d
+Cursor primary key is: 12
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex2
+Cursor key is: c
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex2
+Cursor key is: b
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex2
+Cursor key is: a
+Cursor primary key is: 3
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex2
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+Done
+
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindexcursor1html"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/index-cursor-1.html (0 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-cursor-1.html                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-cursor-1.html        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -0,0 +1,133 @@
</span><ins>+This tests cursors that iterate over entire indexes.&lt;br&gt;
+&lt;div id=&quot;logger&quot;&gt;&lt;/div&gt;
+&lt;script&gt;
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+function done()
+{
+    log(&quot;Done&quot;);
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function log(message)
+{
+    document.getElementById(&quot;logger&quot;).innerHTML += message + &quot;&lt;br&gt;&quot;;
+}
+
+function logCursor(cursor)
+{
+    log(&quot;Cursor direction is: &quot; + cursor.direction);
+    log(&quot;Cursor source is: &quot; + cursor.source.name);    
+    log(&quot;Cursor key is: &quot; + cursor.key);    
+    log(&quot;Cursor primary key is: &quot; + cursor.primaryKey);
+    log(&quot;Cursor value is: &quot; + cursor.value);  
+}
+
+function setupRequest(request)
+{
+    request.onsuccess = function() {
+        log(&quot;Success opening or iterating cursor&quot;);
+        logCursor(request.result);  
+        if (request.result.key != undefined)
+            request.result.continue();
+        else
+            startNextCursor();
+    }
+    request.onerror = function(e) {
+        log(&quot;Unexpected error opening or iterating cursor&quot;);
+        logCursor(request.result);
+        done();
+    } 
+}
+
+function testCursorDirection(index, direction)
+{
+    var range = IDBKeyRange.lowerBound(-Infinity);
+    var request = index.openCursor(range, direction);
+    setupRequest(request);
+}
+
+var index1;
+var index2;
+
+var cursorCommands = [
+    &quot;testCursorDirection(index2, 'prevunique')&quot;,
+    &quot;testCursorDirection(index1, 'prevunique')&quot;,
+    &quot;testCursorDirection(index2, 'prev')&quot;,
+    &quot;testCursorDirection(index1, 'prev')&quot;,
+    &quot;testCursorDirection(index2, 'nextunique')&quot;,
+    &quot;testCursorDirection(index1, 'nextunique')&quot;,
+    &quot;testCursorDirection(index2, 'next')&quot;,
+    &quot;testCursorDirection(index1, 'next')&quot;,
+];
+
+function startNextCursor()
+{
+    if (!cursorCommands.length) {
+        done();
+        return;
+    }
+    
+    var command = cursorCommands.pop();
+    log (&quot;&quot;);
+    log(&quot;Starting a new cursor: &quot; + command);
+    eval(command);
+}
+    
+var createRequest = window.indexedDB.open(&quot;IndexCursor1Database&quot;, 1);
+createRequest.onupgradeneeded = function(event) {
+    log(&quot;Initial upgrade needed: Old version - &quot; + event.oldVersion + &quot; New version - &quot; + event.newVersion);
+
+    var versionTransaction = createRequest.transaction;
+    var database = event.target.result;
+    var objectStore = database.createObjectStore(&quot;TestObjectStore&quot;);
+    index1 = objectStore.createIndex(&quot;TestIndex1&quot;, &quot;bar&quot;);
+    index2 = objectStore.createIndex(&quot;TestIndex2&quot;, &quot;baz&quot;);
+
+    objectStore.put({ bar: &quot;A&quot;, baz: &quot;a&quot; }, 1);
+    objectStore.put({ bar: &quot;A&quot;, baz: &quot;a&quot; }, 3);
+    objectStore.put({ bar: &quot;A&quot;, baz: &quot;a&quot; }, 2);
+    objectStore.put({ bar: &quot;B&quot;, baz: &quot;b&quot; }, 5);
+    objectStore.put({ bar: &quot;B&quot;, baz: &quot;b&quot; }, 6);
+    objectStore.put({ bar: &quot;B&quot;, baz: &quot;b&quot; }, 4);
+    objectStore.put({ bar: &quot;C&quot;, baz: &quot;c&quot; }, 7);
+    objectStore.put({ bar: &quot;C&quot;, baz: &quot;c&quot; }, 9);
+    objectStore.put({ bar: &quot;C&quot;, baz: &quot;c&quot; }, 8);
+    objectStore.put({ bar: &quot;D&quot;, baz: &quot;d&quot; }, 11);
+    objectStore.put({ bar: &quot;D&quot;, baz: &quot;d&quot; }, 12);
+    objectStore.put({ bar: &quot;D&quot;, baz: &quot;d&quot; }, 10);
+
+    var req1 = index1.count();
+    req1.onsuccess = function() {
+        log(&quot;TestIndex1 count is: &quot; + req1.result);
+    }
+
+    var req2 = index2.count();
+    req2.onsuccess = function() {
+        log(&quot;TestIndex2 count is: &quot; + req2.result);
+    }
+    
+    startNextCursor();
+    
+    versionTransaction.onabort = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected aborted&quot;);
+        done();
+    }
+
+    versionTransaction.oncomplete = function(event) {
+        log(&quot;Initial upgrade versionchange transaction complete&quot;);
+        done();
+    }
+
+    versionTransaction.onerror = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected error&quot; + event);
+        done();
+    }
+}
+
+&lt;/script&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindexcursor2expectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/index-cursor-2-expected.txt (0 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-cursor-2-expected.txt                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-cursor-2-expected.txt        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -0,0 +1,549 @@
</span><ins>+This tests cursors that iterate over parts of indexes.
+Initial upgrade needed: Old version - 0 New version - 1
+
+Starting a new cursor: testCursorDirection('next', IDBKeyRange.bound('B', 'D', true, true))
+TestIndex1 count is: 12
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 8
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('nextunique', IDBKeyRange.bound('B', 'D', true, true))
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('prev', IDBKeyRange.bound('B', 'D', true, true))
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 8
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('prevunique', IDBKeyRange.bound('B', 'D', true, true))
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('next', IDBKeyRange.bound('B', 'C'))
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 5
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 8
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('nextunique', IDBKeyRange.bound('B', 'C'))
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('prev', IDBKeyRange.bound('B', 'C'))
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 8
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 5
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('prevunique', IDBKeyRange.bound('B', 'C'))
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('next', IDBKeyRange.upperBound('B'))
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 2
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 3
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 5
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('nextunique', IDBKeyRange.upperBound('B'))
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('prev', IDBKeyRange.upperBound('B'))
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 5
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 3
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 2
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('prevunique', IDBKeyRange.upperBound('B'))
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 3
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('next', IDBKeyRange.lowerBound('C'))
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 8
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 10
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 11
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 12
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('nextunique', IDBKeyRange.lowerBound('C'))
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 10
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('prev', IDBKeyRange.lowerBound('C'))
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 12
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 11
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 10
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 8
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('prevunique', IDBKeyRange.lowerBound('C'))
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 12
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('next', IDBKeyRange.only('B'))
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 5
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('nextunique', IDBKeyRange.only('B'))
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('prev', IDBKeyRange.only('B'))
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 5
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection('prevunique', IDBKeyRange.only('B'))
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+Done
+
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindexcursor2html"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/index-cursor-2.html (0 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-cursor-2.html                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-cursor-2.html        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -0,0 +1,137 @@
</span><ins>+This tests cursors that iterate over parts of indexes.&lt;br&gt;
+&lt;div id=&quot;logger&quot;&gt;&lt;/div&gt;
+&lt;script&gt;
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+function done()
+{
+    log(&quot;Done&quot;);
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function log(message)
+{
+    document.getElementById(&quot;logger&quot;).innerHTML += message + &quot;&lt;br&gt;&quot;;
+}
+
+function logCursor(cursor)
+{
+    log(&quot;Cursor direction is: &quot; + cursor.direction);
+    log(&quot;Cursor source is: &quot; + cursor.source.name);    
+    log(&quot;Cursor key is: &quot; + cursor.key);    
+    log(&quot;Cursor primary key is: &quot; + cursor.primaryKey);
+    log(&quot;Cursor value is: &quot; + cursor.value);  
+}
+
+function setupRequest(request)
+{
+    request.onsuccess = function() {
+        log(&quot;Success opening or iterating cursor&quot;);
+        logCursor(request.result);  
+        if (request.result.key != undefined)
+            request.result.continue();
+        else
+            startNextCursor();
+    }
+    request.onerror = function(e) {
+        log(&quot;Unexpected error opening or iterating cursor&quot;);
+        logCursor(request.result);
+        done();
+    } 
+}
+
+var index;
+
+function testCursorDirection(direction, range)
+{
+    var request = index.openCursor(range, direction);
+    setupRequest(request);
+}
+
+var cursorCommands = [
+    &quot;testCursorDirection('prevunique', IDBKeyRange.only('B'))&quot;,
+    &quot;testCursorDirection('prev', IDBKeyRange.only('B'))&quot;,
+    &quot;testCursorDirection('nextunique', IDBKeyRange.only('B'))&quot;,
+    &quot;testCursorDirection('next', IDBKeyRange.only('B'))&quot;,
+    &quot;testCursorDirection('prevunique', IDBKeyRange.lowerBound('C'))&quot;,
+    &quot;testCursorDirection('prev', IDBKeyRange.lowerBound('C'))&quot;,
+    &quot;testCursorDirection('nextunique', IDBKeyRange.lowerBound('C'))&quot;,
+    &quot;testCursorDirection('next', IDBKeyRange.lowerBound('C'))&quot;,
+    &quot;testCursorDirection('prevunique', IDBKeyRange.upperBound('B'))&quot;,
+    &quot;testCursorDirection('prev', IDBKeyRange.upperBound('B'))&quot;,
+    &quot;testCursorDirection('nextunique', IDBKeyRange.upperBound('B'))&quot;,
+    &quot;testCursorDirection('next', IDBKeyRange.upperBound('B'))&quot;,
+    &quot;testCursorDirection('prevunique', IDBKeyRange.bound('B', 'C'))&quot;,
+    &quot;testCursorDirection('prev', IDBKeyRange.bound('B', 'C'))&quot;,
+    &quot;testCursorDirection('nextunique', IDBKeyRange.bound('B', 'C'))&quot;,
+    &quot;testCursorDirection('next', IDBKeyRange.bound('B', 'C'))&quot;,
+    &quot;testCursorDirection('prevunique', IDBKeyRange.bound('B', 'D', true, true))&quot;,
+    &quot;testCursorDirection('prev', IDBKeyRange.bound('B', 'D', true, true))&quot;,
+    &quot;testCursorDirection('nextunique', IDBKeyRange.bound('B', 'D', true, true))&quot;,
+    &quot;testCursorDirection('next', IDBKeyRange.bound('B', 'D', true, true))&quot;,
+];
+
+function startNextCursor()
+{
+    if (!cursorCommands.length) {
+        done();
+        return;
+    }
+
+    var command = cursorCommands.pop();
+    log (&quot;&quot;);
+    log(&quot;Starting a new cursor: &quot; + command);
+    eval(command);
+}
+    
+var createRequest = window.indexedDB.open(&quot;IndexCursor2Database&quot;, 1);
+createRequest.onupgradeneeded = function(event) {
+    log(&quot;Initial upgrade needed: Old version - &quot; + event.oldVersion + &quot; New version - &quot; + event.newVersion);
+
+    var versionTransaction = createRequest.transaction;
+    var database = event.target.result;
+    var objectStore = database.createObjectStore(&quot;TestObjectStore&quot;);
+    index = objectStore.createIndex(&quot;TestIndex1&quot;, &quot;bar&quot;);
+
+    objectStore.put({ bar: &quot;A&quot;, baz: &quot;a&quot; }, 1);
+    objectStore.put({ bar: &quot;A&quot;, baz: &quot;a&quot; }, 3);
+    objectStore.put({ bar: &quot;A&quot;, baz: &quot;a&quot; }, 2);
+    objectStore.put({ bar: &quot;B&quot;, baz: &quot;b&quot; }, 5);
+    objectStore.put({ bar: &quot;B&quot;, baz: &quot;b&quot; }, 6);
+    objectStore.put({ bar: &quot;B&quot;, baz: &quot;b&quot; }, 4);
+    objectStore.put({ bar: &quot;C&quot;, baz: &quot;c&quot; }, 7);
+    objectStore.put({ bar: &quot;C&quot;, baz: &quot;c&quot; }, 9);
+    objectStore.put({ bar: &quot;C&quot;, baz: &quot;c&quot; }, 8);
+    objectStore.put({ bar: &quot;D&quot;, baz: &quot;d&quot; }, 11);
+    objectStore.put({ bar: &quot;D&quot;, baz: &quot;d&quot; }, 12);
+    objectStore.put({ bar: &quot;D&quot;, baz: &quot;d&quot; }, 10);
+
+    var req = index.count();
+    req.onsuccess = function() {
+        log(&quot;TestIndex1 count is: &quot; + req.result);
+    }
+
+    startNextCursor();
+    
+    versionTransaction.onabort = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected aborted&quot;);
+        done();
+    }
+
+    versionTransaction.oncomplete = function(event) {
+        log(&quot;Initial upgrade versionchange transaction complete&quot;);
+        done();
+    }
+
+    versionTransaction.onerror = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected error&quot; + event);
+        done();
+    }
+}
+
+&lt;/script&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindexcursor3expectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/index-cursor-3-expected.txt (0 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-cursor-3-expected.txt                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-cursor-3-expected.txt        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -0,0 +1,319 @@
</span><ins>+This tests that index cursors properly handle changing indexes.
+Initial upgrade needed: Old version - 0 New version - 1
+
+Starting a new cursor: testCursorDirection(index, 'next')
+
+TestIndex1 count is: 18
+
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 2
+Cursor value is: [object Object]
+Deleted key 2 from object store
+Deleted key 3 from object store
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Deleted key 4 from object store
+Deleted key 5 from object store
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Deleted key 6 from object store
+Deleted key 7 from object store
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 8
+Cursor value is: [object Object]
+Deleted key 8 from object store
+Deleted key 9 from object store
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: E
+Cursor primary key is: 10
+Cursor value is: [object Object]
+Deleted key 10 from object store
+Deleted key 11 from object store
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: F
+Cursor primary key is: 12
+Cursor value is: [object Object]
+Deleted key 12 from object store
+Deleted key 13 from object store
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: G
+Cursor primary key is: 14
+Cursor value is: [object Object]
+Deleted key 14 from object store
+Deleted key 15 from object store
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: H
+Cursor primary key is: 16
+Cursor value is: [object Object]
+Deleted key 16 from object store
+Deleted key 17 from object store
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: I
+Cursor primary key is: 18
+Cursor value is: [object Object]
+Deleted key 18 from object store
+Success opening or iterating cursor
+Cursor direction is: next
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection(index, 'prev')
+
+TestIndex1 count is: 18
+
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: I
+Cursor primary key is: 18
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: I
+Cursor primary key is: 17
+Cursor value is: [object Object]
+Deleted key 17 from object store
+Deleted key 16 from object store
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: H
+Cursor primary key is: 15
+Cursor value is: [object Object]
+Deleted key 15 from object store
+Deleted key 14 from object store
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: G
+Cursor primary key is: 13
+Cursor value is: [object Object]
+Deleted key 13 from object store
+Deleted key 12 from object store
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: F
+Cursor primary key is: 11
+Cursor value is: [object Object]
+Deleted key 11 from object store
+Deleted key 10 from object store
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: E
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Deleted key 9 from object store
+Deleted key 8 from object store
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Deleted key 7 from object store
+Deleted key 6 from object store
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 5
+Cursor value is: [object Object]
+Deleted key 5 from object store
+Deleted key 4 from object store
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 3
+Cursor value is: [object Object]
+Deleted key 3 from object store
+Deleted key 2 from object store
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Deleted key 1 from object store
+Success opening or iterating cursor
+Cursor direction is: prev
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection(index, 'nextunique')
+
+TestIndex1 count is: 18
+
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 3
+Cursor value is: [object Object]
+Deleted key 3 from object store
+Deleted key 4 from object store
+Deleted key 5 from object store
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: C
+Cursor primary key is: 6
+Cursor value is: [object Object]
+Deleted key 6 from object store
+Deleted key 7 from object store
+Deleted key 8 from object store
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: E
+Cursor primary key is: 9
+Cursor value is: [object Object]
+Deleted key 9 from object store
+Deleted key 10 from object store
+Deleted key 11 from object store
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: F
+Cursor primary key is: 12
+Cursor value is: [object Object]
+Deleted key 12 from object store
+Deleted key 13 from object store
+Deleted key 14 from object store
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: H
+Cursor primary key is: 15
+Cursor value is: [object Object]
+Deleted key 15 from object store
+Deleted key 16 from object store
+Deleted key 17 from object store
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: I
+Cursor primary key is: 18
+Cursor value is: [object Object]
+Deleted key 18 from object store
+Deleted key 1 from object store
+Success opening or iterating cursor
+Cursor direction is: nextunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+
+Starting a new cursor: testCursorDirection(index, 'prevunique')
+
+TestIndex1 count is: 18
+
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: I
+Cursor primary key is: 18
+Cursor value is: [object Object]
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: H
+Cursor primary key is: 16
+Cursor value is: [object Object]
+Deleted key 16 from object store
+Deleted key 15 from object store
+Deleted key 14 from object store
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: G
+Cursor primary key is: 13
+Cursor value is: [object Object]
+Deleted key 13 from object store
+Deleted key 12 from object store
+Deleted key 11 from object store
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: E
+Cursor primary key is: 10
+Cursor value is: [object Object]
+Deleted key 10 from object store
+Deleted key 9 from object store
+Deleted key 8 from object store
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: D
+Cursor primary key is: 7
+Cursor value is: [object Object]
+Deleted key 7 from object store
+Deleted key 6 from object store
+Deleted key 5 from object store
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: B
+Cursor primary key is: 4
+Cursor value is: [object Object]
+Deleted key 4 from object store
+Deleted key 3 from object store
+Deleted key 2 from object store
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: A
+Cursor primary key is: 1
+Cursor value is: [object Object]
+Deleted key 1 from object store
+Success opening or iterating cursor
+Cursor direction is: prevunique
+Cursor source is: TestIndex1
+Cursor key is: undefined
+Cursor primary key is: undefined
+Cursor value is: undefined
+Done
+
</ins></span></pre></div>
<a id="trunkLayoutTestsstorageindexeddbmodernindexcursor3html"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/storage/indexeddb/modern/index-cursor-3.html (0 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/storage/indexeddb/modern/index-cursor-3.html                                (rev 0)
+++ trunk/LayoutTests/storage/indexeddb/modern/index-cursor-3.html        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -0,0 +1,176 @@
</span><ins>+This tests that index cursors properly handle changing indexes.&lt;br&gt;
+&lt;div id=&quot;logger&quot;&gt;&lt;/div&gt;
+&lt;script&gt;
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+function done()
+{
+    log(&quot;Done&quot;);
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function log(message)
+{
+    document.getElementById(&quot;logger&quot;).innerHTML += message + &quot;&lt;br&gt;&quot;;
+}
+
+var index;
+var objectStore;
+
+function logCursor(cursor)
+{
+    log(&quot;Cursor direction is: &quot; + cursor.direction);
+    log(&quot;Cursor source is: &quot; + cursor.source.name);    
+    log(&quot;Cursor key is: &quot; + cursor.key);    
+    log(&quot;Cursor primary key is: &quot; + cursor.primaryKey);
+    log(&quot;Cursor value is: &quot; + cursor.value);  
+}
+
+function setupRequest(request)
+{
+    request.onsuccess = function() {
+        log(&quot;Success opening or iterating cursor&quot;);
+        logCursor(request.result);
+
+        if (request.iteratedOnce) {
+            var primaryKey = request.result.primaryKey;
+            if (primaryKey) {
+                objectStore.delete(primaryKey).onsuccess = function() {
+                    log(&quot;Deleted key &quot; + primaryKey + &quot; from object store&quot;);
+                }
+                var nextPrimaryKey = primaryKey;
+                if (request.result.direction.startsWith(&quot;next&quot;)) {
+                    nextPrimaryKey++;
+                    if (nextPrimaryKey &gt; 18)
+                        nextPrimaryKey = 0;
+                } else
+                    nextPrimaryKey--;
+
+                if (nextPrimaryKey &gt; 0) {
+                    objectStore.delete(nextPrimaryKey).onsuccess = function() {
+                        log(&quot;Deleted key &quot; + nextPrimaryKey + &quot; from object store&quot;);
+                    }
+                }
+                
+                // Delete an additional item for unique cursors to make sure they iterate deeper into the sets
+                // of primary keys and/or skip some index keys altogether.
+                if (request.result.direction.endsWith(&quot;unique&quot;)) {                
+                    var nextNextPrimaryKey = nextPrimaryKey;
+                    if (request.result.direction.startsWith(&quot;next&quot;)) {
+                        nextNextPrimaryKey++;
+                        if (nextNextPrimaryKey &gt; 18)
+                            nextNextPrimaryKey = 0;
+                    } else
+                        nextNextPrimaryKey--;
+
+                    if (nextNextPrimaryKey &gt; 0) {
+                        objectStore.delete(nextNextPrimaryKey).onsuccess = function() {
+                            log(&quot;Deleted key &quot; + nextNextPrimaryKey + &quot; from object store&quot;);
+                        }
+                    }
+                }
+            }
+        }
+     
+        request.iteratedOnce = true;
+
+        if (request.result.key != undefined)
+            request.result.continue();
+        else
+            startNextCursor();
+    }
+    request.onerror = function(e) {
+        log(&quot;Unexpected error opening or iterating cursor&quot;);
+        logCursor(request.result);
+        done();
+    } 
+}
+
+function testCursorDirection(index, direction)
+{
+    var range = IDBKeyRange.lowerBound(-Infinity);
+    var request = index.openCursor(range, direction);
+    setupRequest(request);
+}
+
+var cursorCommands = [
+    &quot;testCursorDirection(index, 'prevunique')&quot;,
+    &quot;testCursorDirection(index, 'nextunique')&quot;,
+    &quot;testCursorDirection(index, 'prev')&quot;,
+    &quot;testCursorDirection(index, 'next')&quot;,
+];
+
+function startNextCursor()
+{
+    if (!cursorCommands.length) {
+        done();
+        return;
+    }
+    
+    populateObjectStore();
+
+    var command = cursorCommands.pop();
+    log(&quot;&lt;br&gt;Starting a new cursor: &quot; + command);
+    var req = index.count();
+    req.onsuccess = function() {
+        log(&quot;&lt;br&gt;TestIndex1 count is: &quot; + req.result + &quot;&lt;br&gt;&quot;);
+    }
+    
+    eval(command);
+}
+
+function populateObjectStore()
+{
+    objectStore.put({ bar: &quot;A&quot; }, 1);
+    objectStore.put({ bar: &quot;A&quot; }, 2);
+    objectStore.put({ bar: &quot;B&quot; }, 3);
+    objectStore.put({ bar: &quot;B&quot; }, 4);
+    objectStore.put({ bar: &quot;C&quot; }, 5);
+    objectStore.put({ bar: &quot;C&quot; }, 6);
+    objectStore.put({ bar: &quot;D&quot; }, 7);
+    objectStore.put({ bar: &quot;D&quot; }, 8);
+    objectStore.put({ bar: &quot;E&quot; }, 9);
+    objectStore.put({ bar: &quot;E&quot; }, 10);
+    objectStore.put({ bar: &quot;F&quot; }, 11);
+    objectStore.put({ bar: &quot;F&quot; }, 12);
+    objectStore.put({ bar: &quot;G&quot; }, 13);
+    objectStore.put({ bar: &quot;G&quot; }, 14);    
+    objectStore.put({ bar: &quot;H&quot; }, 15);
+    objectStore.put({ bar: &quot;H&quot; }, 16);  
+    objectStore.put({ bar: &quot;I&quot; }, 17);
+    objectStore.put({ bar: &quot;I&quot; }, 18);  
+}
+
+var createRequest = window.indexedDB.open(&quot;IndexCursor3Database&quot;, 1);
+createRequest.onupgradeneeded = function(event) {
+    log(&quot;Initial upgrade needed: Old version - &quot; + event.oldVersion + &quot; New version - &quot; + event.newVersion);
+
+    var versionTransaction = createRequest.transaction;
+    var database = event.target.result;
+    objectStore = database.createObjectStore(&quot;TestObjectStore&quot;);
+    index = objectStore.createIndex(&quot;TestIndex1&quot;, &quot;bar&quot;);
+    
+    startNextCursor();
+    
+    versionTransaction.onabort = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected aborted&quot;);
+        done();
+    }
+
+    versionTransaction.oncomplete = function(event) {
+        log(&quot;Initial upgrade versionchange transaction complete&quot;);
+        done();
+    }
+
+    versionTransaction.onerror = function(event) {
+        log(&quot;Initial upgrade versionchange transaction unexpected error&quot; + event);
+        done();
+    }
+}
+
+&lt;/script&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/CMakeLists.txt (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/CMakeLists.txt        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/CMakeLists.txt        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -909,6 +909,7 @@
</span><span class="cx">     Modules/indexeddb/server/MemoryCursor.cpp
</span><span class="cx">     Modules/indexeddb/server/MemoryIDBBackingStore.cpp
</span><span class="cx">     Modules/indexeddb/server/MemoryIndex.cpp
</span><ins>+    Modules/indexeddb/server/MemoryIndexCursor.cpp
</ins><span class="cx">     Modules/indexeddb/server/MemoryObjectStore.cpp
</span><span class="cx">     Modules/indexeddb/server/MemoryObjectStoreCursor.cpp
</span><span class="cx">     Modules/indexeddb/server/UniqueIDBDatabase.cpp
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/ChangeLog        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -1,3 +1,93 @@
</span><ins>+2015-11-18  Brady Eidson  &lt;beidson@apple.com&gt;
+
+        Modern IDB:Make in-memory Index cursors work.
+        https://bugs.webkit.org/show_bug.cgi?id=151278
+
+        Reviewed by Alex Christensen.
+
+        Tests: storage/indexeddb/modern/index-cursor-1.html
+               storage/indexeddb/modern/index-cursor-2.html
+               storage/indexeddb/modern/index-cursor-3.html
+
+        * CMakeLists.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+
+        * Modules/indexeddb/client/IDBIndexImpl.cpp:
+        (WebCore::IDBClient::IDBIndex::openCursor):
+        (WebCore::IDBClient::IDBIndex::openKeyCursor):
+        
+        * Modules/indexeddb/server/IndexValueEntry.cpp:
+        (WebCore::IDBServer::IndexValueEntry::removeKey):
+        (WebCore::IDBServer::IndexValueEntry::Iterator::Iterator):
+        (WebCore::IDBServer::IndexValueEntry::Iterator::key):
+        (WebCore::IDBServer::IndexValueEntry::Iterator::isValid):
+        (WebCore::IDBServer::IndexValueEntry::Iterator::invalidate):
+        (WebCore::IDBServer::IndexValueEntry::Iterator::operator++):
+        (WebCore::IDBServer::IndexValueEntry::begin):
+        (WebCore::IDBServer::IndexValueEntry::reverseBegin):
+        (WebCore::IDBServer::IndexValueEntry::find):
+        (WebCore::IDBServer::IndexValueEntry::reverseFind):
+        * Modules/indexeddb/server/IndexValueEntry.h:
+        (WebCore::IDBServer::IndexValueEntry::Iterator::Iterator):
+        (WebCore::IDBServer::IndexValueEntry::unique):
+        
+        * Modules/indexeddb/server/IndexValueStore.cpp:
+        (WebCore::IDBServer::IndexValueStore::removeEntriesWithValueKey):
+        (WebCore::IDBServer::IndexValueStore::lowestKeyWithRecordInRange):
+        (WebCore::IDBServer::IndexValueStore::lowestIteratorInRange):
+        (WebCore::IDBServer::IndexValueStore::highestReverseIteratorInRange):
+        (WebCore::IDBServer::IndexValueStore::find):
+        (WebCore::IDBServer::IndexValueStore::reverseFind):
+        (WebCore::IDBServer::IndexValueStore::Iterator::Iterator):
+        (WebCore::IDBServer::IndexValueStore::Iterator::nextIndexEntry):
+        (WebCore::IDBServer::IndexValueStore::Iterator::operator++):
+        (WebCore::IDBServer::IndexValueStore::Iterator::invalidate):
+        (WebCore::IDBServer::IndexValueStore::Iterator::isValid):
+        (WebCore::IDBServer::IndexValueStore::Iterator::key):
+        (WebCore::IDBServer::IndexValueStore::Iterator::primaryKey):
+        * Modules/indexeddb/server/IndexValueStore.h:
+        (WebCore::IDBServer::IndexValueStore::Iterator::Iterator):
+        
+        * Modules/indexeddb/server/MemoryIDBBackingStore.cpp:
+        (WebCore::IDBServer::MemoryIDBBackingStore::openCursor):
+        
+        * Modules/indexeddb/server/MemoryIndex.cpp:
+        (WebCore::IDBServer::MemoryIndex::cursorDidBecomeClean):
+        (WebCore::IDBServer::MemoryIndex::cursorDidBecomeDirty):
+        (WebCore::IDBServer::MemoryIndex::objectStoreCleared):
+        (WebCore::IDBServer::MemoryIndex::notifyCursorsOfValueChange):
+        (WebCore::IDBServer::MemoryIndex::notifyCursorsOfAllRecordsChanged):
+        (WebCore::IDBServer::MemoryIndex::putIndexKey):
+        (WebCore::IDBServer::MemoryIndex::removeRecord):
+        (WebCore::IDBServer::MemoryIndex::removeEntriesWithValueKey):
+        (WebCore::IDBServer::MemoryIndex::maybeOpenCursor):
+        * Modules/indexeddb/server/MemoryIndex.h:
+        (WebCore::IDBServer::MemoryIndex::valueStore):
+        (WebCore::IDBServer::MemoryIndex::objectStore):
+        
+        * Modules/indexeddb/server/MemoryIndexCursor.cpp: Added.
+        (WebCore::IDBServer::MemoryIndexCursor::MemoryIndexCursor):
+        (WebCore::IDBServer::MemoryIndexCursor::~MemoryIndexCursor):
+        (WebCore::IDBServer::MemoryIndexCursor::currentData):
+        (WebCore::IDBServer::MemoryIndexCursor::iterate):
+        (WebCore::IDBServer::MemoryIndexCursor::indexRecordsAllChanged):
+        (WebCore::IDBServer::MemoryIndexCursor::indexValueChanged):
+        * Modules/indexeddb/server/MemoryIndexCursor.h:
+        
+        * Modules/indexeddb/server/MemoryObjectStore.cpp:
+        (WebCore::IDBServer::MemoryObjectStore::indexForIdentifier):
+        (WebCore::IDBServer::MemoryObjectStore::valueForKey):
+        * Modules/indexeddb/server/MemoryObjectStore.h:
+        
+        * Modules/indexeddb/shared/IDBCursorInfo.cpp:
+        (WebCore::IDBCursorInfo::objectStoreCursor):
+        (WebCore::IDBCursorInfo::indexCursor):
+        (WebCore::IDBCursorInfo::IDBCursorInfo):
+        (WebCore::IDBCursorInfo::isDirectionNoDuplicate):
+        (WebCore::IDBCursorInfo::isolatedCopy):
+        * Modules/indexeddb/shared/IDBCursorInfo.h:
+        (WebCore::IDBCursorInfo::objectStoreIdentifier):
+
</ins><span class="cx"> 2015-11-18  Antti Koivisto  &lt;antti@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Assertion failure in RenderTreePosition::computeNextSibling
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbclientIDBIndexImplcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/client/IDBIndexImpl.cpp (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/client/IDBIndexImpl.cpp        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/Modules/indexeddb/client/IDBIndexImpl.cpp        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -104,7 +104,13 @@
</span><span class="cx">     if (ec)
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><del>-    auto info = IDBCursorInfo::indexCursor(m_objectStore-&gt;modernTransaction(), m_info.identifier(), range, direction, IndexedDB::CursorType::KeyAndValue);
</del><ins>+    IDBKeyRangeData rangeData = range;
+    if (rangeData.lowerKey.isNull())
+        rangeData.lowerKey = IDBKeyData::minimum();
+    if (rangeData.upperKey.isNull())
+        rangeData.upperKey = IDBKeyData::maximum();
+
+    auto info = IDBCursorInfo::indexCursor(m_objectStore-&gt;modernTransaction(), m_objectStore-&gt;info().identifier(), m_info.identifier(), rangeData, direction, IndexedDB::CursorType::KeyAndValue);
</ins><span class="cx">     Ref&lt;IDBRequest&gt; request = m_objectStore-&gt;modernTransaction().requestOpenCursor(*context, *this, info);
</span><span class="cx">     return WTF::move(request);
</span><span class="cx"> }
</span><span class="lines">@@ -202,7 +208,7 @@
</span><span class="cx">     if (ec)
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><del>-    auto info = IDBCursorInfo::indexCursor(m_objectStore-&gt;modernTransaction(), m_info.identifier(), range, direction, IndexedDB::CursorType::KeyOnly);
</del><ins>+    auto info = IDBCursorInfo::indexCursor(m_objectStore-&gt;modernTransaction(), m_objectStore-&gt;info().identifier(), m_info.identifier(), range, direction, IndexedDB::CursorType::KeyOnly);
</ins><span class="cx">     Ref&lt;IDBRequest&gt; request = m_objectStore-&gt;modernTransaction().requestOpenCursor(*context, *this, info);
</span><span class="cx">     return WTF::move(request);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIndexValueEntrycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.cpp (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.cpp        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.cpp        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -61,14 +61,17 @@
</span><span class="cx"> 
</span><span class="cx"> bool IndexValueEntry::removeKey(const IDBKeyData&amp; key)
</span><span class="cx"> {
</span><del>-    if (m_unique &amp;&amp; m_key &amp;&amp; *m_key == key) {
-        delete m_key;
-        m_key = nullptr;
-        return true;
</del><ins>+    if (m_unique) {
+        if (m_key &amp;&amp; *m_key == key) {
+            delete m_key;
+            m_key = nullptr;
+            return true;
+        }
+
+        return false;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_orderedKeys-&gt;erase(key);
-    return m_orderedKeys-&gt;empty();
</del><ins>+    return m_orderedKeys-&gt;erase(key);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> const IDBKeyData* IndexValueEntry::getLowest() const
</span><span class="lines">@@ -90,6 +93,131 @@
</span><span class="cx">     return m_orderedKeys-&gt;size();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+IndexValueEntry::Iterator::Iterator(IndexValueEntry&amp; entry)
+    : m_entry(&amp;entry)
+{
+    ASSERT(m_entry-&gt;m_key);
+}
+
+IndexValueEntry::Iterator::Iterator(IndexValueEntry&amp; entry, std::set&lt;IDBKeyData&gt;::iterator iterator)
+    : m_entry(&amp;entry)
+    , m_forwardIterator(iterator)
+{
+}
+
+IndexValueEntry::Iterator::Iterator(IndexValueEntry&amp; entry, std::set&lt;IDBKeyData&gt;::reverse_iterator iterator)
+    : m_entry(&amp;entry)
+    , m_forward(false)
+    , m_reverseIterator(iterator)
+{
+}
+
+const IDBKeyData&amp; IndexValueEntry::Iterator::key() const
+{
+    ASSERT(isValid());
+    if (m_entry-&gt;unique()) {
+        ASSERT(m_entry-&gt;m_key);
+        return *m_entry-&gt;m_key;
+    }
+
+    return m_forward ? *m_forwardIterator : *m_reverseIterator;
+}
+
+bool IndexValueEntry::Iterator::isValid() const
+{
+#ifndef NDEBUG
+    if (m_entry) {
+        if (m_entry-&gt;m_unique)
+            ASSERT(m_entry-&gt;m_key);
+        else
+            ASSERT(m_entry-&gt;m_orderedKeys);
+    }
+#endif
+
+    return m_entry;
+}
+
+void IndexValueEntry::Iterator::invalidate()
+{
+    m_entry = nullptr;
+}
+
+IndexValueEntry::Iterator&amp; IndexValueEntry::Iterator::operator++()
+{
+    if (!isValid())
+        return *this;
+
+    if (m_entry-&gt;m_unique) {
+        invalidate();
+        return *this;
+    }
+
+    if (m_forward) {
+        ++m_forwardIterator;
+        if (m_forwardIterator == m_entry-&gt;m_orderedKeys-&gt;end())
+            invalidate();
+    } else {
+        ++m_reverseIterator;
+        if (m_reverseIterator == m_entry-&gt;m_orderedKeys-&gt;rend())
+            invalidate();
+    }
+
+    return *this;
+}
+
+IndexValueEntry::Iterator IndexValueEntry::begin()
+{
+    if (m_unique) {
+        ASSERT(m_key);
+        return { *this };
+    }
+
+    ASSERT(m_orderedKeys);
+    return { *this, m_orderedKeys-&gt;begin() };
+}
+
+IndexValueEntry::Iterator IndexValueEntry::reverseBegin()
+{
+    if (m_unique) {
+        ASSERT(m_key);
+        return { *this };
+    }
+
+    ASSERT(m_orderedKeys);
+    return { *this, m_orderedKeys-&gt;rbegin() };
+}
+
+IndexValueEntry::Iterator IndexValueEntry::find(const IDBKeyData&amp; key)
+{
+    if (m_unique) {
+        ASSERT(m_key);
+        return *m_key == key ? IndexValueEntry::Iterator(*this) : IndexValueEntry::Iterator();
+    }
+
+    ASSERT(m_orderedKeys);
+    auto iterator = m_orderedKeys-&gt;lower_bound(key);
+    if (iterator == m_orderedKeys-&gt;end())
+        return { };
+
+    return { *this, iterator };
+}
+
+IndexValueEntry::Iterator IndexValueEntry::reverseFind(const IDBKeyData&amp; key)
+{
+    if (m_unique) {
+        ASSERT(m_key);
+        return *m_key == key ? IndexValueEntry::Iterator(*this) : IndexValueEntry::Iterator();
+    }
+
+    ASSERT(m_orderedKeys);
+    auto iterator = std::set&lt;IDBKeyData&gt;::reverse_iterator(m_orderedKeys-&gt;upper_bound(key));
+    if (iterator == m_orderedKeys-&gt;rend())
+        return { };
+
+    return { *this, iterator };
+}
+
+
</ins><span class="cx"> } // namespace IDBServer
</span><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIndexValueEntryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.h (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.h        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.h        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -32,6 +32,9 @@
</span><span class="cx"> #include &lt;set&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><ins>+
+class ThreadSafeDataBuffer;
+
</ins><span class="cx"> namespace IDBServer {
</span><span class="cx"> 
</span><span class="cx"> class IndexValueEntry {
</span><span class="lines">@@ -41,13 +44,48 @@
</span><span class="cx"> 
</span><span class="cx">     void addKey(const IDBKeyData&amp;);
</span><span class="cx"> 
</span><del>-    // Returns true if the IndexValueEntry is empty after removing the key;
</del><ins>+    // Returns true if a key was actually removed.
</ins><span class="cx">     bool removeKey(const IDBKeyData&amp;);
</span><span class="cx"> 
</span><span class="cx">     const IDBKeyData* getLowest() const;
</span><span class="cx"> 
</span><span class="cx">     uint64_t getCount() const;
</span><span class="cx"> 
</span><ins>+    class Iterator {
+    public:
+        Iterator()
+        {
+        }
+
+        Iterator(IndexValueEntry&amp;);
+        Iterator(IndexValueEntry&amp;, std::set&lt;IDBKeyData&gt;::iterator);
+        Iterator(IndexValueEntry&amp;, std::set&lt;IDBKeyData&gt;::reverse_iterator);
+
+        bool isValid() const;
+        void invalidate();
+
+        const IDBKeyData&amp; key() const;
+        const ThreadSafeDataBuffer&amp; value() const;
+
+        Iterator&amp; operator++();
+
+    private:
+        IndexValueEntry* m_entry { nullptr };
+        bool m_forward { true };
+        std::set&lt;IDBKeyData&gt;::iterator m_forwardIterator;
+        std::set&lt;IDBKeyData&gt;::reverse_iterator m_reverseIterator;
+    };
+
+    Iterator begin();
+    Iterator reverseBegin();
+
+    // Finds the key, or the next higher record after the key.
+    Iterator find(const IDBKeyData&amp;);
+    // Finds the key, or the next lowest record before the key.
+    Iterator reverseFind(const IDBKeyData&amp;);
+
+    bool unique() const { return m_unique; }
+
</ins><span class="cx"> private:
</span><span class="cx">     union {
</span><span class="cx">         std::set&lt;IDBKeyData&gt;* m_orderedKeys;
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIndexValueStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.cpp (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.cpp        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.cpp        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -30,6 +30,8 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;IDBError.h&quot;
</span><span class="cx"> #include &quot;IDBKeyRangeData.h&quot;
</span><ins>+#include &quot;Logging.h&quot;
+#include &quot;MemoryIndex.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> namespace IDBServer {
</span><span class="lines">@@ -94,12 +96,14 @@
</span><span class="cx">         m_records.remove(iterator);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void IndexValueStore::removeEntriesWithValueKey(const IDBKeyData&amp; valueKey)
</del><ins>+void IndexValueStore::removeEntriesWithValueKey(MemoryIndex&amp; index, const IDBKeyData&amp; valueKey)
</ins><span class="cx"> {
</span><span class="cx">     HashSet&lt;IDBKeyData*&gt; entryKeysToRemove;
</span><span class="cx"> 
</span><span class="cx">     for (auto&amp; entry : m_records) {
</span><span class="cx">         if (entry.value-&gt;removeKey(valueKey))
</span><ins>+            index.notifyCursorsOfValueChange(entry.key, valueKey);
+        if (!entry.value-&gt;getCount())
</ins><span class="cx">             entryKeysToRemove.add(&amp;entry.key);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -111,30 +115,264 @@
</span><span class="cx"> 
</span><span class="cx"> IDBKeyData IndexValueStore::lowestKeyWithRecordInRange(const IDBKeyRangeData&amp; range) const
</span><span class="cx"> {
</span><ins>+    LOG(IndexedDB, &quot;IndexValueStore::lowestKeyWithRecordInRange - %s&quot;, range.loggingString().utf8().data());
+
</ins><span class="cx">     if (range.isExactlyOneKey())
</span><span class="cx">         return m_records.contains(range.lowerKey) ? range.lowerKey : IDBKeyData();
</span><span class="cx"> 
</span><ins>+    auto iterator = lowestIteratorInRange(range);
+    if (iterator == m_orderedKeys.end())
+        return { };
+
+    return *iterator;
+}
+
+std::set&lt;IDBKeyData&gt;::iterator IndexValueStore::lowestIteratorInRange(const IDBKeyRangeData&amp; range) const
+{
</ins><span class="cx">     auto lowestInRange = m_orderedKeys.lower_bound(range.lowerKey);
</span><span class="cx"> 
</span><span class="cx">     if (lowestInRange == m_orderedKeys.end())
</span><del>-        return { };
</del><ins>+        return lowestInRange;
</ins><span class="cx"> 
</span><del>-    if (range.lowerOpen &amp;&amp; *lowestInRange == range.lowerKey)
</del><ins>+    if (range.lowerOpen &amp;&amp; *lowestInRange == range.lowerKey) {
</ins><span class="cx">         ++lowestInRange;
</span><span class="cx"> 
</span><del>-    if (lowestInRange == m_orderedKeys.end())
-        return { };
</del><ins>+        if (lowestInRange == m_orderedKeys.end())
+            return lowestInRange;
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (!range.upperKey.isNull()) {
</span><span class="cx">         if (lowestInRange-&gt;compare(range.upperKey) &gt; 0)
</span><del>-            return { };
</del><ins>+            return m_orderedKeys.end();
</ins><span class="cx">         if (range.upperOpen &amp;&amp; *lowestInRange == range.upperKey)
</span><del>-            return { };
</del><ins>+            return m_orderedKeys.end();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return *lowestInRange;
</del><ins>+    return lowestInRange;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+std::set&lt;IDBKeyData&gt;::reverse_iterator IndexValueStore::highestReverseIteratorInRange(const IDBKeyRangeData&amp; range) const
+{
+    auto highestInRange = std::set&lt;IDBKeyData&gt;::reverse_iterator(m_orderedKeys.upper_bound(range.upperKey));
+
+    if (highestInRange == m_orderedKeys.rend())
+        return highestInRange;
+
+    if (range.upperOpen &amp;&amp; *highestInRange == range.upperKey) {
+        ++highestInRange;
+
+        if (highestInRange == m_orderedKeys.rend())
+            return highestInRange;
+    }
+
+    if (!range.lowerKey.isNull()) {
+        if (highestInRange-&gt;compare(range.lowerKey) &lt; 0)
+            return m_orderedKeys.rend();
+        if (range.lowerOpen &amp;&amp; *highestInRange == range.lowerKey)
+            return m_orderedKeys.rend();
+    }
+
+    return highestInRange;
+}
+
+IndexValueStore::Iterator IndexValueStore::find(const IDBKeyData&amp; key, bool open)
+{
+    IDBKeyRangeData range;
+    if (!key.isNull())
+        range.lowerKey = key;
+    else
+        range.lowerKey = IDBKeyData::minimum();
+    range.lowerOpen = open;
+
+    auto iterator = lowestIteratorInRange(range);
+    if (iterator == m_orderedKeys.end())
+        return { };
+
+    auto record = m_records.get(*iterator);
+    ASSERT(record);
+
+    auto primaryIterator = record-&gt;begin();
+    ASSERT(primaryIterator.isValid());
+    return { *this, iterator, primaryIterator };
+}
+
+IndexValueStore::Iterator IndexValueStore::find(const IDBKeyData&amp; key, const IDBKeyData&amp; primaryKey)
+{
+    ASSERT(!key.isNull());
+    ASSERT(!primaryKey.isNull());
+
+    IDBKeyRangeData range;
+    range.lowerKey = key;
+    range.lowerOpen = false;
+
+    auto iterator = lowestIteratorInRange(range);
+    if (iterator == m_orderedKeys.end())
+        return { };
+
+    auto record = m_records.get(*iterator);
+    ASSERT(record);
+
+    auto primaryIterator = record-&gt;find(primaryKey);
+    if (primaryIterator.isValid())
+        return { *this, iterator, primaryIterator };
+
+    // If we didn't find a primary key iterator in this entry,
+    // we need to move on to start of the next record.
+    iterator++;
+    if (iterator == m_orderedKeys.end())
+        return { };
+
+    record = m_records.get(*iterator);
+    ASSERT(record);
+
+    primaryIterator = record-&gt;begin();
+    ASSERT(primaryIterator.isValid());
+
+    return { *this, iterator, primaryIterator };
+}
+
+IndexValueStore::Iterator IndexValueStore::reverseFind(const IDBKeyData&amp; key, bool open)
+{
+    IDBKeyRangeData range;
+    if (!key.isNull())
+        range.upperKey = key;
+    else
+        range.upperKey = IDBKeyData::maximum();
+    range.upperOpen = open;
+
+    auto iterator = highestReverseIteratorInRange(range);
+    if (iterator == m_orderedKeys.rend())
+        return { };
+
+    auto record = m_records.get(*iterator);
+    ASSERT(record);
+
+    auto primaryIterator = record-&gt;reverseBegin();
+    ASSERT(primaryIterator.isValid());
+    return { *this, iterator, primaryIterator };
+}
+
+IndexValueStore::Iterator IndexValueStore::reverseFind(const IDBKeyData&amp; key, const IDBKeyData&amp; primaryKey)
+{
+    ASSERT(!key.isNull());
+    ASSERT(!primaryKey.isNull());
+
+    IDBKeyRangeData range;
+    range.upperKey = key;
+    range.upperOpen = false;
+
+    auto iterator = highestReverseIteratorInRange(range);
+    if (iterator == m_orderedKeys.rend())
+        return { };
+
+    auto record = m_records.get(*iterator);
+    ASSERT(record);
+
+    auto primaryIterator = record-&gt;reverseFind(primaryKey);
+    if (primaryIterator.isValid())
+        return { *this, iterator, primaryIterator };
+
+    // If we didn't find a primary key iterator in this entry,
+    // we need to move on to start of the next record.
+    iterator++;
+    if (iterator == m_orderedKeys.rend())
+        return { };
+
+    record = m_records.get(*iterator);
+    ASSERT(record);
+
+    primaryIterator = record-&gt;reverseBegin();
+    ASSERT(primaryIterator.isValid());
+
+    return { *this, iterator, primaryIterator };
+}
+
+
+IndexValueStore::Iterator::Iterator(IndexValueStore&amp; store, std::set&lt;IDBKeyData&gt;::iterator iterator, IndexValueEntry::Iterator primaryIterator)
+    : m_store(&amp;store)
+    , m_forwardIterator(iterator)
+    , m_primaryKeyIterator(primaryIterator)
+{
+}
+
+IndexValueStore::Iterator::Iterator(IndexValueStore&amp; store, std::set&lt;IDBKeyData&gt;::reverse_iterator iterator, IndexValueEntry::Iterator primaryIterator)
+    : m_store(&amp;store)
+    , m_forward(false)
+    , m_reverseIterator(iterator)
+    , m_primaryKeyIterator(primaryIterator)
+{
+}
+
+IndexValueStore::Iterator&amp; IndexValueStore::Iterator::nextIndexEntry()
+{
+    if (!m_store)
+        return *this;
+
+    if (m_forward) {
+        ++m_forwardIterator;
+        if (m_forwardIterator == m_store-&gt;m_orderedKeys.end()) {
+            invalidate();
+            return *this;
+        }
+
+        auto* entry = m_store-&gt;m_records.get(*m_forwardIterator);
+        ASSERT(entry);
+
+        m_primaryKeyIterator = entry-&gt;begin();
+        ASSERT(m_primaryKeyIterator.isValid());
+    } else {
+        ++m_reverseIterator;
+        if (m_reverseIterator == m_store-&gt;m_orderedKeys.rend()) {
+            invalidate();
+            return *this;
+        }
+
+        auto* entry = m_store-&gt;m_records.get(*m_reverseIterator);
+        ASSERT(entry);
+
+        m_primaryKeyIterator = entry-&gt;reverseBegin();
+        ASSERT(m_primaryKeyIterator.isValid());
+    }
+    
+    return *this;
+}
+
+IndexValueStore::Iterator&amp; IndexValueStore::Iterator::operator++()
+{
+    if (!isValid())
+        return *this;
+
+    ++m_primaryKeyIterator;
+    if (m_primaryKeyIterator.isValid())
+        return *this;
+
+    // Ran out of primary key records, so move the main index iterator.
+    return nextIndexEntry();
+}
+
+void IndexValueStore::Iterator::invalidate()
+{
+    m_store = nullptr;
+    m_primaryKeyIterator.invalidate();
+}
+
+bool IndexValueStore::Iterator::isValid()
+{
+    return m_store &amp;&amp; m_primaryKeyIterator.isValid();
+}
+
+const IDBKeyData&amp; IndexValueStore::Iterator::key()
+{
+    ASSERT(isValid());
+    return m_forward ? *m_forwardIterator : *m_reverseIterator;
+}
+
+const IDBKeyData&amp; IndexValueStore::Iterator::primaryKey()
+{
+    ASSERT(isValid());
+    return m_primaryKeyIterator.key();
+}
+
</ins><span class="cx"> } // namespace IDBServer
</span><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverIndexValueStoreh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.h (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.h        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IndexValueStore.h        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -41,6 +41,8 @@
</span><span class="cx"> 
</span><span class="cx"> namespace IDBServer {
</span><span class="cx"> 
</span><ins>+class MemoryIndex;
+
</ins><span class="cx"> typedef HashMap&lt;IDBKeyData, std::unique_ptr&lt;IndexValueEntry&gt;, IDBKeyDataHash, IDBKeyDataHashTraits&gt; IndexKeyValueMap;
</span><span class="cx"> 
</span><span class="cx"> class IndexValueStore {
</span><span class="lines">@@ -55,9 +57,49 @@
</span><span class="cx">     IDBError addRecord(const IDBKeyData&amp; indexKey, const IDBKeyData&amp; valueKey);
</span><span class="cx">     void removeRecord(const IDBKeyData&amp; indexKey, const IDBKeyData&amp; valueKey);
</span><span class="cx"> 
</span><del>-    void removeEntriesWithValueKey(const IDBKeyData&amp; valueKey);
</del><ins>+    void removeEntriesWithValueKey(MemoryIndex&amp;, const IDBKeyData&amp; valueKey);
</ins><span class="cx"> 
</span><ins>+    class Iterator {
+        friend class IndexValueStore;
+    public:
+        Iterator()
+        {
+        }
+
+        Iterator(IndexValueStore&amp;, std::set&lt;IDBKeyData&gt;::iterator, IndexValueEntry::Iterator);
+        Iterator(IndexValueStore&amp;, std::set&lt;IDBKeyData&gt;::reverse_iterator, IndexValueEntry::Iterator);
+
+        void invalidate();
+        bool isValid();
+
+        const IDBKeyData&amp; key();
+        const IDBKeyData&amp; primaryKey();
+        const ThreadSafeDataBuffer&amp; value();
+
+        Iterator&amp; operator++();
+        Iterator&amp; nextIndexEntry();
+
+    private:
+        IndexValueStore* m_store { nullptr };
+        bool m_forward { true };
+        std::set&lt;IDBKeyData&gt;::iterator m_forwardIterator;
+        std::set&lt;IDBKeyData&gt;::reverse_iterator m_reverseIterator;
+
+        IndexValueEntry::Iterator m_primaryKeyIterator;
+    };
+
+    // Returns an iterator pointing to the first primaryKey record in the requested key, or the next key if it doesn't exist.
+    Iterator find(const IDBKeyData&amp;, bool open = false);
+    Iterator reverseFind(const IDBKeyData&amp;, bool open = false);
+
+    // Returns an iterator pointing to the key/primaryKey record, or the next one after it if it doesn't exist.
+    Iterator find(const IDBKeyData&amp;, const IDBKeyData&amp; primaryKey);
+    Iterator reverseFind(const IDBKeyData&amp;, const IDBKeyData&amp; primaryKey);
+
</ins><span class="cx"> private:
</span><ins>+    std::set&lt;IDBKeyData&gt;::iterator lowestIteratorInRange(const IDBKeyRangeData&amp;) const;
+    std::set&lt;IDBKeyData&gt;::reverse_iterator highestReverseIteratorInRange(const IDBKeyRangeData&amp;) const;
+
</ins><span class="cx">     IndexKeyValueMap m_records;
</span><span class="cx">     std::set&lt;IDBKeyData&gt; m_orderedKeys;
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryIDBBackingStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIDBBackingStore.cpp        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -354,7 +354,20 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">     case IndexedDB::CursorSource::Index:
</span><del>-        return IDBError(IDBExceptionCode::Unknown, ASCIILiteral(&quot;Index cursors not yet supported&quot;));
</del><ins>+        auto* objectStore = m_objectStoresByIdentifier.get(info.objectStoreIdentifier());
+        if (!objectStore)
+            return IDBError(IDBExceptionCode::Unknown, ASCIILiteral(&quot;No backing store object store found&quot;));
+
+        auto* index = objectStore-&gt;indexForIdentifier(info.sourceIdentifier());
+        if (!index)
+            return IDBError(IDBExceptionCode::Unknown, ASCIILiteral(&quot;No backing store index found&quot;));
+
+        MemoryCursor* cursor = index-&gt;maybeOpenCursor(info);
+        if (!cursor)
+            return IDBError(IDBExceptionCode::Unknown, ASCIILiteral(&quot;Could not create index cursor in backing store&quot;));
+
+        cursor-&gt;currentData(outData);
+        break;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return { };
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryIndexcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.cpp        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -55,14 +55,44 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void MemoryIndex::cursorDidBecomeClean(MemoryIndexCursor&amp; cursor)
+{
+    m_cleanCursors.add(&amp;cursor);
+}
+
+void MemoryIndex::cursorDidBecomeDirty(MemoryIndexCursor&amp; cursor)
+{
+    m_cleanCursors.remove(&amp;cursor);
+}
+
</ins><span class="cx"> void MemoryIndex::objectStoreCleared()
</span><span class="cx"> {
</span><span class="cx">     auto transaction = m_objectStore.writeTransaction();
</span><span class="cx">     ASSERT(transaction);
</span><span class="cx"> 
</span><span class="cx">     transaction-&gt;indexCleared(*this, WTF::move(m_records));
</span><ins>+
+    notifyCursorsOfAllRecordsChanged();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void MemoryIndex::notifyCursorsOfValueChange(const IDBKeyData&amp; indexKey, const IDBKeyData&amp; primaryKey)
+{
+    Vector&lt;MemoryIndexCursor*&gt; cursors;
+    copyToVector(m_cleanCursors, cursors);
+    for (auto* cursor : cursors)
+        cursor-&gt;indexValueChanged(indexKey, primaryKey);
+}
+
+void MemoryIndex::notifyCursorsOfAllRecordsChanged()
+{
+    Vector&lt;MemoryIndexCursor*&gt; cursors;
+    copyToVector(m_cleanCursors, cursors);
+    for (auto* cursor : cursors)
+        cursor-&gt;indexRecordsAllChanged();
+
+    ASSERT(m_cleanCursors.isEmpty());
+}
+
</ins><span class="cx"> void MemoryIndex::replaceIndexValueStore(std::unique_ptr&lt;IndexValueStore&gt;&amp;&amp; valueStore)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_objectStore.writeTransaction());
</span><span class="lines">@@ -122,12 +152,16 @@
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;MemoryIndex::provisionalPutIndexKey&quot;);
</span><span class="cx"> 
</span><del>-    if (!m_records)
</del><ins>+    if (!m_records) {
</ins><span class="cx">         m_records = std::make_unique&lt;IndexValueStore&gt;(m_info.unique());
</span><ins>+        notifyCursorsOfAllRecordsChanged();
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (!m_info.multiEntry()) {
</span><span class="cx">         IDBKeyData key = indexKey.asOneKey();
</span><del>-        return m_records-&gt;addRecord(key, valueKey);
</del><ins>+        IDBError result = m_records-&gt;addRecord(key, valueKey);
+        notifyCursorsOfValueChange(key, valueKey);
+        return result;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Vector&lt;IDBKeyData&gt; keys = indexKey.multiEntry();
</span><span class="lines">@@ -142,6 +176,7 @@
</span><span class="cx">     for (auto&amp; key : keys) {
</span><span class="cx">         auto error = m_records-&gt;addRecord(key, valueKey);
</span><span class="cx">         ASSERT_UNUSED(error, error.isNull());
</span><ins>+        notifyCursorsOfValueChange(key, valueKey);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return { };
</span><span class="lines">@@ -156,12 +191,15 @@
</span><span class="cx">     if (!m_info.multiEntry()) {
</span><span class="cx">         IDBKeyData key = indexKey.asOneKey();
</span><span class="cx">         m_records-&gt;removeRecord(key, valueKey);
</span><ins>+        notifyCursorsOfValueChange(key, valueKey);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Vector&lt;IDBKeyData&gt; keys = indexKey.multiEntry();
</span><del>-    for (auto&amp; key : keys)
</del><ins>+    for (auto&amp; key : keys) {
</ins><span class="cx">         m_records-&gt;removeRecord(key, valueKey);
</span><ins>+        notifyCursorsOfValueChange(key, valueKey);
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MemoryIndex::removeEntriesWithValueKey(const IDBKeyData&amp; valueKey)
</span><span class="lines">@@ -171,9 +209,19 @@
</span><span class="cx">     if (!m_records)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    m_records-&gt;removeEntriesWithValueKey(valueKey);
</del><ins>+    m_records-&gt;removeEntriesWithValueKey(*this, valueKey);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+MemoryIndexCursor* MemoryIndex::maybeOpenCursor(const IDBCursorInfo&amp; info)
+{
+    auto result = m_cursors.add(info.identifier(), nullptr);
+    if (!result.isNewEntry)
+        return nullptr;
+
+    result.iterator-&gt;value = std::make_unique&lt;MemoryIndexCursor&gt;(*this, info);
+    return result.iterator-&gt;value.get();
+}
+
</ins><span class="cx"> } // namespace IDBServer
</span><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryIndexh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndex.h        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx"> #include &quot;IDBIndexInfo.h&quot;
</span><span class="cx"> #include &quot;IDBKeyData.h&quot;
</span><span class="cx"> #include &quot;IndexValueStore.h&quot;
</span><ins>+#include &quot;MemoryIndexCursor.h&quot;
</ins><span class="cx"> #include &lt;set&gt;
</span><span class="cx"> #include &lt;wtf/HashMap.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -72,15 +73,31 @@
</span><span class="cx">     void objectStoreCleared();
</span><span class="cx">     void replaceIndexValueStore(std::unique_ptr&lt;IndexValueStore&gt;&amp;&amp;);
</span><span class="cx"> 
</span><ins>+    MemoryIndexCursor* maybeOpenCursor(const IDBCursorInfo&amp;);
+
+    IndexValueStore* valueStore() { return m_records.get(); }
+
+    MemoryObjectStore&amp; objectStore() { return m_objectStore; }
+
+    void cursorDidBecomeClean(MemoryIndexCursor&amp;);
+    void cursorDidBecomeDirty(MemoryIndexCursor&amp;);
+
+    void notifyCursorsOfValueChange(const IDBKeyData&amp; indexKey, const IDBKeyData&amp; primaryKey);
+
</ins><span class="cx"> private:
</span><span class="cx">     MemoryIndex(const IDBIndexInfo&amp;, MemoryObjectStore&amp;);
</span><span class="cx"> 
</span><span class="cx">     uint64_t recordCountForKey(const IDBKeyData&amp;) const;
</span><del>-    
</del><ins>+
+    void notifyCursorsOfAllRecordsChanged();
+
</ins><span class="cx">     IDBIndexInfo m_info;
</span><span class="cx">     MemoryObjectStore&amp; m_objectStore;
</span><span class="cx"> 
</span><span class="cx">     std::unique_ptr&lt;IndexValueStore&gt; m_records;
</span><ins>+
+    HashMap&lt;IDBResourceIdentifier, std::unique_ptr&lt;MemoryIndexCursor&gt;&gt; m_cursors;
+    HashSet&lt;MemoryIndexCursor*&gt; m_cleanCursors;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace IDBServer
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryIndexCursorcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp (0 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp                                (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.cpp        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -0,0 +1,205 @@
</span><ins>+/*
+ * Copyright (C) 2015 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 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 &quot;config.h&quot;
+#include &quot;MemoryIndexCursor.h&quot;
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include &quot;IDBCursorInfo.h&quot;
+#include &quot;IndexValueStore.h&quot;
+#include &quot;Logging.h&quot;
+#include &quot;MemoryCursor.h&quot;
+#include &quot;MemoryIndex.h&quot;
+#include &quot;MemoryObjectStore.h&quot;
+
+namespace WebCore {
+namespace IDBServer {
+
+MemoryIndexCursor::MemoryIndexCursor(MemoryIndex&amp; index, const IDBCursorInfo&amp; info)
+    : MemoryCursor(info)
+    , m_index(index)
+{
+    auto* valueStore = m_index.valueStore();
+    if (!valueStore)
+        return;
+
+    IndexValueStore::Iterator iterator;
+    if (m_info.isDirectionForward())
+        iterator = valueStore-&gt;find(m_info.range().lowerKey, m_info.range().lowerOpen);
+    else
+        iterator = valueStore-&gt;reverseFind(m_info.range().upperKey, m_info.range().upperOpen);
+
+    if (iterator.isValid()) {
+        m_currentKey = iterator.key();
+        m_currentPrimaryKey = iterator.primaryKey();
+        m_index.cursorDidBecomeClean(*this);
+    }
+}
+
+MemoryIndexCursor::~MemoryIndexCursor()
+{
+}
+
+void MemoryIndexCursor::currentData(IDBGetResult&amp; getResult)
+{
+    getResult.keyData = m_currentKey;
+    getResult.primaryKeyData = m_currentPrimaryKey;
+    if (m_info.cursorType() == IndexedDB::CursorType::KeyOnly)
+        return;
+
+    getResult.valueBuffer = m_index.objectStore().valueForKey(m_currentPrimaryKey);
+}
+
+void MemoryIndexCursor::iterate(const IDBKeyData&amp; key, uint32_t count, IDBGetResult&amp; getResult)
+{
+    LOG(IndexedDB, &quot;MemoryIndexCursor::iterate to key %s, %u count&quot;, key.loggingString().utf8().data(), count);
+
+    if (key.isValid()) {
+        // Cannot iterator by both a count and to a key
+        ASSERT(!count);
+
+        auto* valueStore = m_index.valueStore();
+        if (!valueStore) {
+            m_currentKey = { };
+            m_currentPrimaryKey = { };
+            getResult = { };
+            return;
+        }
+
+        if (m_info.isDirectionForward())
+            m_currentIterator = valueStore-&gt;find(m_currentKey);
+        else
+            m_currentIterator = valueStore-&gt;reverseFind(m_currentKey);
+
+        if (!m_currentIterator.isValid()) {
+            m_currentKey = { };
+            m_currentPrimaryKey = { };
+            getResult = { };
+            return;
+        }
+
+        m_index.cursorDidBecomeClean(*this);
+
+        m_currentKey = m_currentIterator.key();
+        m_currentPrimaryKey = m_currentIterator.primaryKey();
+        currentData(getResult);
+
+        return;
+    }
+
+    // If there was not a valid key argument and no positive count argument
+    // that means the default iteration count of &quot;1&quot;
+    if (!count)
+        count = 1;
+
+    if (!m_currentIterator.isValid()) {
+        auto* valueStore = m_index.valueStore();
+        if (!valueStore) {
+            m_currentKey = { };
+            m_currentPrimaryKey = { };
+            getResult = { };
+            return;
+        }
+
+        switch (m_info.cursorDirection()) {
+        case IndexedDB::CursorDirection::Next:
+            m_currentIterator = valueStore-&gt;find(m_currentKey, m_currentPrimaryKey);
+            break;
+        case IndexedDB::CursorDirection::NextNoDuplicate:
+            m_currentIterator = valueStore-&gt;find(m_currentKey, true);
+            break;
+        case IndexedDB::CursorDirection::Prev:
+            m_currentIterator = valueStore-&gt;reverseFind(m_currentKey, m_currentPrimaryKey);
+            break;
+        case IndexedDB::CursorDirection::PrevNoDuplicate:
+            m_currentIterator = valueStore-&gt;reverseFind(m_currentKey, true);
+            break;
+        }
+
+        if (!m_currentIterator.isValid()) {
+            m_currentKey = { };
+            m_currentPrimaryKey = { };
+            getResult = { };
+            return;
+        }
+
+        m_index.cursorDidBecomeClean(*this);
+
+        // If we restored the current iterator and it does *not* match the current key/primaryKey,
+        // then it is the next record in line and we should consider that an iteration.
+        if (m_currentKey != m_currentIterator.key() || m_currentPrimaryKey != m_currentIterator.primaryKey())
+            --count;
+    }
+
+    ASSERT(m_currentIterator.isValid());
+
+    while (count) {
+        if (m_info.isDirectionNoDuplicate())
+            m_currentIterator.nextIndexEntry();
+        else
+            ++m_currentIterator;
+
+        if (!m_currentIterator.isValid())
+            break;
+
+        --count;
+    }
+
+    if (m_currentIterator.isValid() &amp;&amp; !m_info.range().containsKey(m_currentIterator.key()))
+        m_currentIterator.invalidate();
+
+    // Not having a valid iterator after finishing any iteration means we've reached the end of the cursor.
+    if (!m_currentIterator.isValid()) {
+        m_currentKey = { };
+        m_currentPrimaryKey = { };
+        getResult = { };
+        return;
+    }
+
+    m_currentKey = m_currentIterator.key();
+    m_currentPrimaryKey = m_currentIterator.primaryKey();
+    currentData(getResult);
+}
+
+void MemoryIndexCursor::indexRecordsAllChanged()
+{
+    m_currentIterator.invalidate();
+    m_index.cursorDidBecomeDirty(*this);
+}
+
+void MemoryIndexCursor::indexValueChanged(const IDBKeyData&amp; key, const IDBKeyData&amp; primaryKey)
+{
+    if (m_currentKey != key || m_currentPrimaryKey != primaryKey)
+        return;
+
+    m_currentIterator.invalidate();
+    m_index.cursorDidBecomeDirty(*this);
+}
+
+} // namespace IDBServer
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
</ins></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryIndexCursorhfromrev192609trunkSourceWebCoreModulesindexeddbserverIndexValueEntryh"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.h (from rev 192609, trunk/Source/WebCore/Modules/indexeddb/server/IndexValueEntry.h) (0 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.h                                (rev 0)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryIndexCursor.h        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -0,0 +1,63 @@
</span><ins>+/*
+ * Copyright (C) 2015 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 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 MemoryIndexCursor_h
+#define MemoryIndexCursor_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include &quot;IDBCursorInfo.h&quot;
+#include &quot;IndexValueStore.h&quot;
+#include &quot;MemoryCursor.h&quot;
+
+namespace WebCore {
+namespace IDBServer {
+
+class MemoryIndex;
+
+class MemoryIndexCursor : public MemoryCursor {
+public:
+    MemoryIndexCursor(MemoryIndex&amp;, const IDBCursorInfo&amp;);
+    virtual ~MemoryIndexCursor();
+
+    void indexRecordsAllChanged();
+    void indexValueChanged(const IDBKeyData&amp; indexKey, const IDBKeyData&amp; primaryKey);
+
+private:
+    virtual void currentData(IDBGetResult&amp;) override final;
+    virtual void iterate(const IDBKeyData&amp;, uint32_t count, IDBGetResult&amp;) override final;
+
+    MemoryIndex&amp; m_index;
+
+    IndexValueStore::Iterator m_currentIterator;
+    IDBKeyData m_currentKey;
+    IDBKeyData m_currentPrimaryKey;
+};
+
+} // namespace IDBServer
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+#endif // MemoryIndexCursor_h
</ins></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryObjectStorecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.cpp        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -58,6 +58,12 @@
</span><span class="cx">     ASSERT(!m_writeTransaction);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+MemoryIndex* MemoryObjectStore::indexForIdentifier(uint64_t identifier)
+{
+    ASSERT(identifier);
+    return m_indexesByIdentifier.get(identifier);
+}
+
</ins><span class="cx"> void MemoryObjectStore::writeTransactionStarted(MemoryBackingStoreTransaction&amp; transaction)
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;MemoryObjectStore::writeTransactionStarted&quot;);
</span><span class="lines">@@ -305,6 +311,14 @@
</span><span class="cx">     return count;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ThreadSafeDataBuffer MemoryObjectStore::valueForKey(const IDBKeyData&amp; key) const
+{
+    if (!m_keyValueStore)
+        return { };
+
+    return m_keyValueStore-&gt;get(key);
+}
+
</ins><span class="cx"> ThreadSafeDataBuffer MemoryObjectStore::valueForKeyRange(const IDBKeyRangeData&amp; keyRangeData) const
</span><span class="cx"> {
</span><span class="cx">     LOG(IndexedDB, &quot;MemoryObjectStore::valueForKey&quot;);
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbserverMemoryObjectStoreh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/Modules/indexeddb/server/MemoryObjectStore.h        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -78,6 +78,7 @@
</span><span class="cx">     void clear();
</span><span class="cx">     void replaceKeyValueStore(std::unique_ptr&lt;KeyValueMap&gt;&amp;&amp;, std::unique_ptr&lt;std::set&lt;IDBKeyData&gt;&gt;&amp;&amp;);
</span><span class="cx"> 
</span><ins>+    ThreadSafeDataBuffer valueForKey(const IDBKeyData&amp;) const;
</ins><span class="cx">     ThreadSafeDataBuffer valueForKeyRange(const IDBKeyRangeData&amp;) const;
</span><span class="cx">     IDBGetResult indexValueForKeyRange(uint64_t indexIdentifier, IndexedDB::IndexRecordType, const IDBKeyRangeData&amp;) const;
</span><span class="cx">     uint64_t countForKeyRange(uint64_t indexIdentifier, const IDBKeyRangeData&amp;) const;
</span><span class="lines">@@ -88,6 +89,8 @@
</span><span class="cx"> 
</span><span class="cx">     std::set&lt;IDBKeyData&gt;* orderedKeys() { return m_orderedKeys.get(); }
</span><span class="cx"> 
</span><ins>+    MemoryIndex* indexForIdentifier(uint64_t);
+
</ins><span class="cx"> private:
</span><span class="cx">     MemoryObjectStore(const IDBObjectStoreInfo&amp;);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbsharedIDBCursorInfocpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/shared/IDBCursorInfo.cpp (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/shared/IDBCursorInfo.cpp        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IDBCursorInfo.cpp        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -35,28 +35,42 @@
</span><span class="cx"> 
</span><span class="cx"> IDBCursorInfo IDBCursorInfo::objectStoreCursor(IDBClient::IDBTransaction&amp; transaction, uint64_t objectStoreIdentifier, const IDBKeyRangeData&amp; range, IndexedDB::CursorDirection direction)
</span><span class="cx"> {
</span><del>-    return { transaction, IndexedDB::CursorSource::ObjectStore, objectStoreIdentifier, range, direction, IndexedDB::CursorType::KeyAndValue };
</del><ins>+    return { transaction, objectStoreIdentifier, range, direction, IndexedDB::CursorType::KeyAndValue };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-IDBCursorInfo IDBCursorInfo::indexCursor(IDBClient::IDBTransaction&amp; transaction, uint64_t indexIdentifier, const IDBKeyRangeData&amp; range, IndexedDB::CursorDirection direction, IndexedDB::CursorType type)
</del><ins>+IDBCursorInfo IDBCursorInfo::indexCursor(IDBClient::IDBTransaction&amp; transaction, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData&amp; range, IndexedDB::CursorDirection direction, IndexedDB::CursorType type)
</ins><span class="cx"> {
</span><del>-    return { transaction, IndexedDB::CursorSource::Index, indexIdentifier, range, direction, type };
</del><ins>+    return { transaction, objectStoreIdentifier, indexIdentifier, range, direction, type };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-IDBCursorInfo::IDBCursorInfo(IDBClient::IDBTransaction&amp; transaction, IndexedDB::CursorSource source, uint64_t sourceIdentifier, const IDBKeyRangeData&amp; range, IndexedDB::CursorDirection direction, IndexedDB::CursorType type)
</del><ins>+IDBCursorInfo::IDBCursorInfo(IDBClient::IDBTransaction&amp; transaction, uint64_t objectStoreIdentifier, const IDBKeyRangeData&amp; range, IndexedDB::CursorDirection direction, IndexedDB::CursorType type)
</ins><span class="cx">     : m_cursorIdentifier(transaction.serverConnection())
</span><span class="cx">     , m_transactionIdentifier(transaction.info().identifier())
</span><del>-    , m_sourceIdentifier(sourceIdentifier)
</del><ins>+    , m_objectStoreIdentifier(objectStoreIdentifier)
+    , m_sourceIdentifier(objectStoreIdentifier)
</ins><span class="cx">     , m_range(range)
</span><del>-    , m_source(source)
</del><ins>+    , m_source(IndexedDB::CursorSource::ObjectStore)
</ins><span class="cx">     , m_direction(direction)
</span><span class="cx">     , m_type(type)
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-IDBCursorInfo::IDBCursorInfo(const IDBResourceIdentifier&amp; cursorIdentifier, const IDBResourceIdentifier&amp; transactionIdentifier, uint64_t sourceIdentifier, const IDBKeyRangeData&amp; range, IndexedDB::CursorSource source, IndexedDB::CursorDirection direction, IndexedDB::CursorType type)
</del><ins>+IDBCursorInfo::IDBCursorInfo(IDBClient::IDBTransaction&amp; transaction, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData&amp; range, IndexedDB::CursorDirection direction, IndexedDB::CursorType type)
+    : m_cursorIdentifier(transaction.serverConnection())
+    , m_transactionIdentifier(transaction.info().identifier())
+    , m_objectStoreIdentifier(objectStoreIdentifier)
+    , m_sourceIdentifier(indexIdentifier)
+    , m_range(range)
+    , m_source(IndexedDB::CursorSource::Index)
+    , m_direction(direction)
+    , m_type(type)
+{
+}
+
+IDBCursorInfo::IDBCursorInfo(const IDBResourceIdentifier&amp; cursorIdentifier, const IDBResourceIdentifier&amp; transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t sourceIdentifier, const IDBKeyRangeData&amp; range, IndexedDB::CursorSource source, IndexedDB::CursorDirection direction, IndexedDB::CursorType type)
</ins><span class="cx">     : m_cursorIdentifier(cursorIdentifier)
</span><span class="cx">     , m_transactionIdentifier(transactionIdentifier)
</span><ins>+    , m_objectStoreIdentifier(objectStoreIdentifier)
</ins><span class="cx">     , m_sourceIdentifier(sourceIdentifier)
</span><span class="cx">     , m_range(range)
</span><span class="cx">     , m_source(source)
</span><span class="lines">@@ -70,9 +84,14 @@
</span><span class="cx">     return m_direction == IndexedDB::CursorDirection::Next || m_direction == IndexedDB::CursorDirection::NextNoDuplicate;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool IDBCursorInfo::isDirectionNoDuplicate() const
+{
+    return m_direction == IndexedDB::CursorDirection::NextNoDuplicate || m_direction == IndexedDB::CursorDirection::PrevNoDuplicate;
+}
+
</ins><span class="cx"> IDBCursorInfo IDBCursorInfo::isolatedCopy() const
</span><span class="cx"> {
</span><del>-    return { m_cursorIdentifier.isolatedCopy(), m_transactionIdentifier.isolatedCopy(), m_sourceIdentifier, m_range.isolatedCopy(), m_source, m_direction, m_type };
</del><ins>+    return { m_cursorIdentifier.isolatedCopy(), m_transactionIdentifier.isolatedCopy(), m_objectStoreIdentifier, m_sourceIdentifier, m_range.isolatedCopy(), m_source, m_direction, m_type };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesindexeddbsharedIDBCursorInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/indexeddb/shared/IDBCursorInfo.h (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/indexeddb/shared/IDBCursorInfo.h        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/Modules/indexeddb/shared/IDBCursorInfo.h        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -48,10 +48,11 @@
</span><span class="cx"> class IDBCursorInfo {
</span><span class="cx"> public:
</span><span class="cx">     static IDBCursorInfo objectStoreCursor(IDBClient::IDBTransaction&amp;, uint64_t objectStoreIdentifier, const IDBKeyRangeData&amp;, IndexedDB::CursorDirection);
</span><del>-    static IDBCursorInfo indexCursor(IDBClient::IDBTransaction&amp;, uint64_t indexIdentifier, const IDBKeyRangeData&amp;, IndexedDB::CursorDirection, IndexedDB::CursorType);
</del><ins>+    static IDBCursorInfo indexCursor(IDBClient::IDBTransaction&amp;, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData&amp;, IndexedDB::CursorDirection, IndexedDB::CursorType);
</ins><span class="cx"> 
</span><span class="cx">     IDBResourceIdentifier identifier() const { return m_cursorIdentifier; }
</span><span class="cx">     uint64_t sourceIdentifier() const { return m_sourceIdentifier; }
</span><ins>+    uint64_t objectStoreIdentifier() const { return m_objectStoreIdentifier; }
</ins><span class="cx"> 
</span><span class="cx">     IndexedDB::CursorSource cursorSource() const { return m_source; }
</span><span class="cx">     IndexedDB::CursorDirection cursorDirection() const { return m_direction; }
</span><span class="lines">@@ -59,15 +60,19 @@
</span><span class="cx">     const IDBKeyRangeData&amp; range() const { return m_range; }
</span><span class="cx"> 
</span><span class="cx">     bool isDirectionForward() const;
</span><ins>+    bool isDirectionNoDuplicate() const;
</ins><span class="cx"> 
</span><span class="cx">     IDBCursorInfo isolatedCopy() const;
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    IDBCursorInfo(IDBClient::IDBTransaction&amp;, IndexedDB::CursorSource, uint64_t sourceIdentifier, const IDBKeyRangeData&amp;, IndexedDB::CursorDirection, IndexedDB::CursorType);
-    IDBCursorInfo(const IDBResourceIdentifier&amp;, const IDBResourceIdentifier&amp;, uint64_t, const IDBKeyRangeData&amp;, IndexedDB::CursorSource, IndexedDB::CursorDirection, IndexedDB::CursorType);
</del><ins>+    IDBCursorInfo(IDBClient::IDBTransaction&amp;, uint64_t objectStoreIdentifier, const IDBKeyRangeData&amp;, IndexedDB::CursorDirection, IndexedDB::CursorType);
+    IDBCursorInfo(IDBClient::IDBTransaction&amp;, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData&amp;, IndexedDB::CursorDirection, IndexedDB::CursorType);
</ins><span class="cx"> 
</span><ins>+    IDBCursorInfo(const IDBResourceIdentifier&amp;, const IDBResourceIdentifier&amp;, uint64_t, uint64_t, const IDBKeyRangeData&amp;, IndexedDB::CursorSource, IndexedDB::CursorDirection, IndexedDB::CursorType);
+
</ins><span class="cx">     IDBResourceIdentifier m_cursorIdentifier;
</span><span class="cx">     IDBResourceIdentifier m_transactionIdentifier;
</span><ins>+    uint64_t m_objectStoreIdentifier;
</ins><span class="cx">     uint64_t m_sourceIdentifier;
</span><span class="cx"> 
</span><span class="cx">     IDBKeyRangeData m_range;
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (192609 => 192610)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2015-11-19 04:15:04 UTC (rev 192609)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2015-11-19 04:36:00 UTC (rev 192610)
</span><span class="lines">@@ -130,7 +130,7 @@
</span><span class="cx">                 071E49701AD5AB5E008A50B4 /* MediaPlaybackTargetMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 071E496F1AD5AB5E008A50B4 /* MediaPlaybackTargetMac.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0720B0A014D3323500642955 /* GenericEventQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0720B09E14D3323500642955 /* GenericEventQueue.cpp */; };
</span><span class="cx">                 0720B0A114D3323500642955 /* GenericEventQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0720B09F14D3323500642955 /* GenericEventQueue.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><del>-                072560FB1BFC2482004F9359 /* JSMediaTrackSupportedConstraintsCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07C1C0E61BFB90A700BD2256 /* JSMediaTrackSupportedConstraintsCustom.cpp */; settings = {ASSET_TAGS = (); }; };
</del><ins>+                072560FB1BFC2482004F9359 /* JSMediaTrackSupportedConstraintsCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07C1C0E61BFB90A700BD2256 /* JSMediaTrackSupportedConstraintsCustom.cpp */; };
</ins><span class="cx">                 07277E4C17D018CC0015534D /* JSMediaStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07277E4017D018CC0015534D /* JSMediaStream.cpp */; };
</span><span class="cx">                 07277E4D17D018CC0015534D /* JSMediaStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 07277E4117D018CC0015534D /* JSMediaStream.h */; };
</span><span class="cx">                 07277E4E17D018CC0015534D /* JSMediaStreamAudioDestinationNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07277E4217D018CC0015534D /* JSMediaStreamAudioDestinationNode.cpp */; };
</span><span class="lines">@@ -212,8 +212,8 @@
</span><span class="cx">                 07846342145B151A00A58DF1 /* JSTrackEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07846340145B151A00A58DF1 /* JSTrackEvent.cpp */; };
</span><span class="cx">                 07846343145B151A00A58DF1 /* JSTrackEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 07846341145B151A00A58DF1 /* JSTrackEvent.h */; };
</span><span class="cx">                 07846385145B1B8E00A58DF1 /* JSTrackCustom.h in Headers */ = {isa = PBXBuildFile; fileRef = 07846384145B1B8E00A58DF1 /* JSTrackCustom.h */; };
</span><del>-                0787C4691BFBDF6F006DCD7F /* JSMediaTrackSupportedConstraints.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0787C4671BFBDF6F006DCD7F /* JSMediaTrackSupportedConstraints.cpp */; settings = {ASSET_TAGS = (); }; };
-                0787C46A1BFBDF6F006DCD7F /* JSMediaTrackSupportedConstraints.h in Headers */ = {isa = PBXBuildFile; fileRef = 0787C4681BFBDF6F006DCD7F /* JSMediaTrackSupportedConstraints.h */; settings = {ASSET_TAGS = (); }; };
</del><ins>+                0787C4691BFBDF6F006DCD7F /* JSMediaTrackSupportedConstraints.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0787C4671BFBDF6F006DCD7F /* JSMediaTrackSupportedConstraints.cpp */; };
+                0787C46A1BFBDF6F006DCD7F /* JSMediaTrackSupportedConstraints.h in Headers */ = {isa = PBXBuildFile; fileRef = 0787C4681BFBDF6F006DCD7F /* JSMediaTrackSupportedConstraints.h */; };
</ins><span class="cx">                 078E08FE17D14CEE00420AA1 /* MediaConstraintsImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07221B4A17CEC32700848E51 /* MediaConstraintsImpl.cpp */; };
</span><span class="cx">                 078E08FF17D14CEE00420AA1 /* MediaStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07221B4C17CEC32700848E51 /* MediaStream.cpp */; };
</span><span class="cx">                 078E090017D14CEE00420AA1 /* MediaStreamEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07221B4F17CEC32700848E51 /* MediaStreamEvent.cpp */; };
</span><span class="lines">@@ -317,7 +317,7 @@
</span><span class="cx">                 07B5A2DC1464320A00A81ECE /* JSTextTrackList.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B5A2DA1464320A00A81ECE /* JSTextTrackList.h */; };
</span><span class="cx">                 07B5A30D14687D7100A81ECE /* JSTextTrackListCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07B5A30C14687D7100A81ECE /* JSTextTrackListCustom.cpp */; };
</span><span class="cx">                 07BDD6EC1469B4C2009C9F85 /* JSTrackEventCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07B5A30A14687B8400A81ECE /* JSTrackEventCustom.cpp */; };
</span><del>-                07C1C0E21BFB600100BD2256 /* MediaTrackSupportedConstraints.h in Headers */ = {isa = PBXBuildFile; fileRef = 07C1C0E01BFB600100BD2256 /* MediaTrackSupportedConstraints.h */; settings = {ASSET_TAGS = (); }; };
</del><ins>+                07C1C0E21BFB600100BD2256 /* MediaTrackSupportedConstraints.h in Headers */ = {isa = PBXBuildFile; fileRef = 07C1C0E01BFB600100BD2256 /* MediaTrackSupportedConstraints.h */; };
</ins><span class="cx">                 07C1C0E51BFB60ED00BD2256 /* RealtimeMediaSourceSupportedConstraints.h in Headers */ = {isa = PBXBuildFile; fileRef = 07C1C0E41BFB60ED00BD2256 /* RealtimeMediaSourceSupportedConstraints.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 07C59B6817F784BA000FBCBB /* MediaSourceStates.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07C59B6517F784BA000FBCBB /* MediaSourceStates.cpp */; };
</span><span class="cx">                 07C59B6917F784BA000FBCBB /* MediaSourceStates.h in Headers */ = {isa = PBXBuildFile; fileRef = 07C59B6617F784BA000FBCBB /* MediaSourceStates.h */; };
</span><span class="lines">@@ -2137,6 +2137,8 @@
</span><span class="cx">                 518F5004194CAC3A0081BAAE /* JSGamepadButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 518F5000194CAC3A0081BAAE /* JSGamepadButton.h */; };
</span><span class="cx">                 518F97021BE94C630023187C /* MemoryIndex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 518F97001BE94C5B0023187C /* MemoryIndex.cpp */; };
</span><span class="cx">                 518F97031BE94C630023187C /* MemoryIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 518F97011BE94C5B0023187C /* MemoryIndex.h */; };
</span><ins>+                519755F91BFD7DC3003DE980 /* MemoryIndexCursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 519755F71BFD7DBC003DE980 /* MemoryIndexCursor.cpp */; };
+                519755FA1BFD7DC3003DE980 /* MemoryIndexCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = 519755F81BFD7DBC003DE980 /* MemoryIndexCursor.h */; };
</ins><span class="cx">                 5198F7A41BBDB79300E2CC5F /* UniqueIDBDatabaseConnection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5198F7A21BBDAA2900E2CC5F /* UniqueIDBDatabaseConnection.cpp */; };
</span><span class="cx">                 5198F7A51BBDB79300E2CC5F /* UniqueIDBDatabaseConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 5198F7A31BBDAA2900E2CC5F /* UniqueIDBDatabaseConnection.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 5198F7A81BBDD38500E2CC5F /* UniqueIDBDatabaseTransaction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5198F7A61BBDD38100E2CC5F /* UniqueIDBDatabaseTransaction.cpp */; };
</span><span class="lines">@@ -2365,24 +2367,24 @@
</span><span class="cx">                 5DFE8F560D16477B0076E937 /* ScheduledAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCA378BA0D15F64200B793D6 /* ScheduledAction.cpp */; };
</span><span class="cx">                 5DFE8F570D16477C0076E937 /* ScheduledAction.h in Headers */ = {isa = PBXBuildFile; fileRef = BCA378BB0D15F64200B793D6 /* ScheduledAction.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 5DFEBAB718592B6D00C75BEB /* WebKitAvailability.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DFEBAB618592B6D00C75BEB /* WebKitAvailability.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><del>-                5E16A2E41BFA650B0029A21E /* MediaEndpointPeerConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E16A2E31BFA64FB0029A21E /* MediaEndpointPeerConnection.h */; settings = {ASSET_TAGS = (); }; };
-                5E16A2E51BFA650F0029A21E /* MediaEndpointPeerConnection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E16A2E21BFA64FB0029A21E /* MediaEndpointPeerConnection.cpp */; settings = {ASSET_TAGS = (); }; };
-                5E2C43511BCEE2F60001E2BC /* PeerConnectionBackend.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C434D1BCEE2E50001E2BC /* PeerConnectionBackend.h */; settings = {ASSET_TAGS = (); }; };
-                5E2C43521BCEE2F60001E2BC /* PeerConnectionStates.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C434E1BCEE2E50001E2BC /* PeerConnectionStates.h */; settings = {ASSET_TAGS = (); }; };
-                5E2C43531BCEE2F60001E2BC /* RTCConfiguration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C434F1BCEE2E50001E2BC /* RTCConfiguration.cpp */; settings = {ASSET_TAGS = (); }; };
-                5E2C435F1BCEE31E0001E2BC /* RTCRtpSenderReceiverBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C435D1BCEE30D0001E2BC /* RTCRtpSenderReceiverBase.h */; settings = {ASSET_TAGS = (); }; };
-                5E2C43601BCEE3230001E2BC /* RTCRtpSender.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C43591BCEE30D0001E2BC /* RTCRtpSender.cpp */; settings = {ASSET_TAGS = (); }; };
-                5E2C43611BCEE3230001E2BC /* RTCRtpSender.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C435A1BCEE30D0001E2BC /* RTCRtpSender.h */; settings = {ASSET_TAGS = (); }; };
-                5E2C43621BCEE32B0001E2BC /* RTCRtpReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C43561BCEE30D0001E2BC /* RTCRtpReceiver.cpp */; settings = {ASSET_TAGS = (); }; };
-                5E2C43631BCEE32B0001E2BC /* RTCRtpReceiver.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43571BCEE30D0001E2BC /* RTCRtpReceiver.h */; settings = {ASSET_TAGS = (); }; };
-                5E2C43671BCEE3770001E2BC /* RTCTrackEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C43641BCEE3720001E2BC /* RTCTrackEvent.cpp */; settings = {ASSET_TAGS = (); }; };
-                5E2C43681BCEE3770001E2BC /* RTCTrackEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43651BCEE3720001E2BC /* RTCTrackEvent.h */; settings = {ASSET_TAGS = (); }; };
-                5E2C436B1BCF071E0001E2BC /* JSRTCTrackEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C43691BCF05C80001E2BC /* JSRTCTrackEvent.cpp */; settings = {ASSET_TAGS = (); }; };
-                5E2C436C1BCF071E0001E2BC /* JSRTCTrackEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C436A1BCF05C80001E2BC /* JSRTCTrackEvent.h */; settings = {ASSET_TAGS = (); }; };
-                5E2C43711BCF0D750001E2BC /* JSRTCRtpReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C436D1BCF0D690001E2BC /* JSRTCRtpReceiver.cpp */; settings = {ASSET_TAGS = (); }; };
-                5E2C43721BCF0D750001E2BC /* JSRTCRtpReceiver.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C436E1BCF0D690001E2BC /* JSRTCRtpReceiver.h */; settings = {ASSET_TAGS = (); }; };
-                5E2C43731BCF0D750001E2BC /* JSRTCRtpSender.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C436F1BCF0D690001E2BC /* JSRTCRtpSender.cpp */; settings = {ASSET_TAGS = (); }; };
-                5E2C43741BCF0D750001E2BC /* JSRTCRtpSender.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43701BCF0D690001E2BC /* JSRTCRtpSender.h */; settings = {ASSET_TAGS = (); }; };
</del><ins>+                5E16A2E41BFA650B0029A21E /* MediaEndpointPeerConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E16A2E31BFA64FB0029A21E /* MediaEndpointPeerConnection.h */; };
+                5E16A2E51BFA650F0029A21E /* MediaEndpointPeerConnection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E16A2E21BFA64FB0029A21E /* MediaEndpointPeerConnection.cpp */; };
+                5E2C43511BCEE2F60001E2BC /* PeerConnectionBackend.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C434D1BCEE2E50001E2BC /* PeerConnectionBackend.h */; };
+                5E2C43521BCEE2F60001E2BC /* PeerConnectionStates.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C434E1BCEE2E50001E2BC /* PeerConnectionStates.h */; };
+                5E2C43531BCEE2F60001E2BC /* RTCConfiguration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C434F1BCEE2E50001E2BC /* RTCConfiguration.cpp */; };
+                5E2C435F1BCEE31E0001E2BC /* RTCRtpSenderReceiverBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C435D1BCEE30D0001E2BC /* RTCRtpSenderReceiverBase.h */; };
+                5E2C43601BCEE3230001E2BC /* RTCRtpSender.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C43591BCEE30D0001E2BC /* RTCRtpSender.cpp */; };
+                5E2C43611BCEE3230001E2BC /* RTCRtpSender.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C435A1BCEE30D0001E2BC /* RTCRtpSender.h */; };
+                5E2C43621BCEE32B0001E2BC /* RTCRtpReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C43561BCEE30D0001E2BC /* RTCRtpReceiver.cpp */; };
+                5E2C43631BCEE32B0001E2BC /* RTCRtpReceiver.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43571BCEE30D0001E2BC /* RTCRtpReceiver.h */; };
+                5E2C43671BCEE3770001E2BC /* RTCTrackEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C43641BCEE3720001E2BC /* RTCTrackEvent.cpp */; };
+                5E2C43681BCEE3770001E2BC /* RTCTrackEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43651BCEE3720001E2BC /* RTCTrackEvent.h */; };
+                5E2C436B1BCF071E0001E2BC /* JSRTCTrackEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C43691BCF05C80001E2BC /* JSRTCTrackEvent.cpp */; };
+                5E2C436C1BCF071E0001E2BC /* JSRTCTrackEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C436A1BCF05C80001E2BC /* JSRTCTrackEvent.h */; };
+                5E2C43711BCF0D750001E2BC /* JSRTCRtpReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C436D1BCF0D690001E2BC /* JSRTCRtpReceiver.cpp */; };
+                5E2C43721BCF0D750001E2BC /* JSRTCRtpReceiver.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C436E1BCF0D690001E2BC /* JSRTCRtpReceiver.h */; };
+                5E2C43731BCF0D750001E2BC /* JSRTCRtpSender.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E2C436F1BCF0D690001E2BC /* JSRTCRtpSender.cpp */; };
+                5E2C43741BCF0D750001E2BC /* JSRTCRtpSender.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43701BCF0D690001E2BC /* JSRTCRtpSender.h */; };
</ins><span class="cx">                 5E2C437B1BCF9A570001E2BC /* RTCPeerConnectionBuiltins.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43761BCF9A0B0001E2BC /* RTCPeerConnectionBuiltins.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 5E2C437C1BCF9A840001E2BC /* RTCPeerConnectionInternalsBuiltins.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E2C43791BCF9A0B0001E2BC /* RTCPeerConnectionInternalsBuiltins.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 5EA725D21ACABD4700EAD17B /* MediaDevices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5EA725CD1ACABCD900EAD17B /* MediaDevices.cpp */; };
</span><span class="lines">@@ -9559,6 +9561,8 @@
</span><span class="cx">                 518F5000194CAC3A0081BAAE /* JSGamepadButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGamepadButton.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 518F97001BE94C5B0023187C /* MemoryIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryIndex.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 518F97011BE94C5B0023187C /* MemoryIndex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryIndex.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                519755F71BFD7DBC003DE980 /* MemoryIndexCursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryIndexCursor.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                519755F81BFD7DBC003DE980 /* MemoryIndexCursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryIndexCursor.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 5198F7A21BBDAA2900E2CC5F /* UniqueIDBDatabaseConnection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UniqueIDBDatabaseConnection.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 5198F7A31BBDAA2900E2CC5F /* UniqueIDBDatabaseConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UniqueIDBDatabaseConnection.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 5198F7A61BBDD38100E2CC5F /* UniqueIDBDatabaseTransaction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UniqueIDBDatabaseTransaction.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -16973,6 +16977,8 @@
</span><span class="cx">                                 51BA4AC91BBC5B9E00DF3D6D /* MemoryIDBBackingStore.h */,
</span><span class="cx">                                 518F97001BE94C5B0023187C /* MemoryIndex.cpp */,
</span><span class="cx">                                 518F97011BE94C5B0023187C /* MemoryIndex.h */,
</span><ins>+                                519755F71BFD7DBC003DE980 /* MemoryIndexCursor.cpp */,
+                                519755F81BFD7DBC003DE980 /* MemoryIndexCursor.h */,
</ins><span class="cx">                                 51771DFC1BDB475600CAE8E4 /* MemoryObjectStore.cpp */,
</span><span class="cx">                                 51771DFD1BDB475600CAE8E4 /* MemoryObjectStore.h */,
</span><span class="cx">                                 517139031BF64DE3000D5F01 /* MemoryObjectStoreCursor.cpp */,
</span><span class="lines">@@ -25833,6 +25839,7 @@
</span><span class="cx">                                 0707568C142262D600414161 /* HTMLTrackElement.h in Headers */,
</span><span class="cx">                                 977B37261228721700B81FF8 /* HTMLTreeBuilder.h in Headers */,
</span><span class="cx">                                 A8EA79F20A1916DF00A8EF5F /* HTMLUListElement.h in Headers */,
</span><ins>+                                519755FA1BFD7DC3003DE980 /* MemoryIndexCursor.h in Headers */,
</ins><span class="cx">                                 AD49914318F0815100BF0092 /* HTMLUnknownElement.h in Headers */,
</span><span class="cx">                                 E44613AB0CD6331000FADA75 /* HTMLVideoElement.h in Headers */,
</span><span class="cx">                                 839AAFED1A0C0C8D00605F99 /* HTMLWBRElement.h in Headers */,
</span><span class="lines">@@ -31005,6 +31012,7 @@
</span><span class="cx">                                 51ABAE1F103C1913008C5260 /* SocketStreamHandleCFNet.cpp in Sources */,
</span><span class="cx">                                 E45390470EAFD637003695C8 /* SoundIOS.mm in Sources */,
</span><span class="cx">                                 4B3043C90AE0371D00A82647 /* SoundMac.mm in Sources */,
</span><ins>+                                519755F91BFD7DC3003DE980 /* MemoryIndexCursor.cpp in Sources */,
</ins><span class="cx">                                 84A81F3D0FC7DFF000955300 /* SourceAlpha.cpp in Sources */,
</span><span class="cx">                                 CD3A496117A9D01B00274E42 /* SourceBuffer.cpp in Sources */,
</span><span class="cx">                                 CD3A496417A9D01B00274E42 /* SourceBufferList.cpp in Sources */,
</span></span></pre>
</div>
</div>

</body>
</html>