<!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 <beidson@apple.com>
+
+ 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 <antti@apple.com>
</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.<br>
+<div id="logger"></div>
+<script>
+
+if (window.testRunner) {
+ testRunner.waitUntilDone();
+ testRunner.dumpAsText();
+}
+
+function done()
+{
+ log("Done");
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+function log(message)
+{
+ document.getElementById("logger").innerHTML += message + "<br>";
+}
+
+function logCursor(cursor)
+{
+ log("Cursor direction is: " + cursor.direction);
+ log("Cursor source is: " + cursor.source.name);
+ log("Cursor key is: " + cursor.key);
+ log("Cursor primary key is: " + cursor.primaryKey);
+ log("Cursor value is: " + cursor.value);
+}
+
+function setupRequest(request)
+{
+ request.onsuccess = function() {
+ log("Success opening or iterating cursor");
+ logCursor(request.result);
+ if (request.result.key != undefined)
+ request.result.continue();
+ else
+ startNextCursor();
+ }
+ request.onerror = function(e) {
+ log("Unexpected error opening or iterating cursor");
+ 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 = [
+ "testCursorDirection(index2, 'prevunique')",
+ "testCursorDirection(index1, 'prevunique')",
+ "testCursorDirection(index2, 'prev')",
+ "testCursorDirection(index1, 'prev')",
+ "testCursorDirection(index2, 'nextunique')",
+ "testCursorDirection(index1, 'nextunique')",
+ "testCursorDirection(index2, 'next')",
+ "testCursorDirection(index1, 'next')",
+];
+
+function startNextCursor()
+{
+ if (!cursorCommands.length) {
+ done();
+ return;
+ }
+
+ var command = cursorCommands.pop();
+ log ("");
+ log("Starting a new cursor: " + command);
+ eval(command);
+}
+
+var createRequest = window.indexedDB.open("IndexCursor1Database", 1);
+createRequest.onupgradeneeded = function(event) {
+ log("Initial upgrade needed: Old version - " + event.oldVersion + " New version - " + event.newVersion);
+
+ var versionTransaction = createRequest.transaction;
+ var database = event.target.result;
+ var objectStore = database.createObjectStore("TestObjectStore");
+ index1 = objectStore.createIndex("TestIndex1", "bar");
+ index2 = objectStore.createIndex("TestIndex2", "baz");
+
+ objectStore.put({ bar: "A", baz: "a" }, 1);
+ objectStore.put({ bar: "A", baz: "a" }, 3);
+ objectStore.put({ bar: "A", baz: "a" }, 2);
+ objectStore.put({ bar: "B", baz: "b" }, 5);
+ objectStore.put({ bar: "B", baz: "b" }, 6);
+ objectStore.put({ bar: "B", baz: "b" }, 4);
+ objectStore.put({ bar: "C", baz: "c" }, 7);
+ objectStore.put({ bar: "C", baz: "c" }, 9);
+ objectStore.put({ bar: "C", baz: "c" }, 8);
+ objectStore.put({ bar: "D", baz: "d" }, 11);
+ objectStore.put({ bar: "D", baz: "d" }, 12);
+ objectStore.put({ bar: "D", baz: "d" }, 10);
+
+ var req1 = index1.count();
+ req1.onsuccess = function() {
+ log("TestIndex1 count is: " + req1.result);
+ }
+
+ var req2 = index2.count();
+ req2.onsuccess = function() {
+ log("TestIndex2 count is: " + req2.result);
+ }
+
+ startNextCursor();
+
+ versionTransaction.onabort = function(event) {
+ log("Initial upgrade versionchange transaction unexpected aborted");
+ done();
+ }
+
+ versionTransaction.oncomplete = function(event) {
+ log("Initial upgrade versionchange transaction complete");
+ done();
+ }
+
+ versionTransaction.onerror = function(event) {
+ log("Initial upgrade versionchange transaction unexpected error" + event);
+ done();
+ }
+}
+
+</script>
</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.<br>
+<div id="logger"></div>
+<script>
+
+if (window.testRunner) {
+ testRunner.waitUntilDone();
+ testRunner.dumpAsText();
+}
+
+function done()
+{
+ log("Done");
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+function log(message)
+{
+ document.getElementById("logger").innerHTML += message + "<br>";
+}
+
+function logCursor(cursor)
+{
+ log("Cursor direction is: " + cursor.direction);
+ log("Cursor source is: " + cursor.source.name);
+ log("Cursor key is: " + cursor.key);
+ log("Cursor primary key is: " + cursor.primaryKey);
+ log("Cursor value is: " + cursor.value);
+}
+
+function setupRequest(request)
+{
+ request.onsuccess = function() {
+ log("Success opening or iterating cursor");
+ logCursor(request.result);
+ if (request.result.key != undefined)
+ request.result.continue();
+ else
+ startNextCursor();
+ }
+ request.onerror = function(e) {
+ log("Unexpected error opening or iterating cursor");
+ logCursor(request.result);
+ done();
+ }
+}
+
+var index;
+
+function testCursorDirection(direction, range)
+{
+ var request = index.openCursor(range, direction);
+ setupRequest(request);
+}
+
+var cursorCommands = [
+ "testCursorDirection('prevunique', IDBKeyRange.only('B'))",
+ "testCursorDirection('prev', IDBKeyRange.only('B'))",
+ "testCursorDirection('nextunique', IDBKeyRange.only('B'))",
+ "testCursorDirection('next', IDBKeyRange.only('B'))",
+ "testCursorDirection('prevunique', IDBKeyRange.lowerBound('C'))",
+ "testCursorDirection('prev', IDBKeyRange.lowerBound('C'))",
+ "testCursorDirection('nextunique', IDBKeyRange.lowerBound('C'))",
+ "testCursorDirection('next', IDBKeyRange.lowerBound('C'))",
+ "testCursorDirection('prevunique', IDBKeyRange.upperBound('B'))",
+ "testCursorDirection('prev', IDBKeyRange.upperBound('B'))",
+ "testCursorDirection('nextunique', IDBKeyRange.upperBound('B'))",
+ "testCursorDirection('next', IDBKeyRange.upperBound('B'))",
+ "testCursorDirection('prevunique', IDBKeyRange.bound('B', 'C'))",
+ "testCursorDirection('prev', IDBKeyRange.bound('B', 'C'))",
+ "testCursorDirection('nextunique', IDBKeyRange.bound('B', 'C'))",
+ "testCursorDirection('next', IDBKeyRange.bound('B', 'C'))",
+ "testCursorDirection('prevunique', IDBKeyRange.bound('B', 'D', true, true))",
+ "testCursorDirection('prev', IDBKeyRange.bound('B', 'D', true, true))",
+ "testCursorDirection('nextunique', IDBKeyRange.bound('B', 'D', true, true))",
+ "testCursorDirection('next', IDBKeyRange.bound('B', 'D', true, true))",
+];
+
+function startNextCursor()
+{
+ if (!cursorCommands.length) {
+ done();
+ return;
+ }
+
+ var command = cursorCommands.pop();
+ log ("");
+ log("Starting a new cursor: " + command);
+ eval(command);
+}
+
+var createRequest = window.indexedDB.open("IndexCursor2Database", 1);
+createRequest.onupgradeneeded = function(event) {
+ log("Initial upgrade needed: Old version - " + event.oldVersion + " New version - " + event.newVersion);
+
+ var versionTransaction = createRequest.transaction;
+ var database = event.target.result;
+ var objectStore = database.createObjectStore("TestObjectStore");
+ index = objectStore.createIndex("TestIndex1", "bar");
+
+ objectStore.put({ bar: "A", baz: "a" }, 1);
+ objectStore.put({ bar: "A", baz: "a" }, 3);
+ objectStore.put({ bar: "A", baz: "a" }, 2);
+ objectStore.put({ bar: "B", baz: "b" }, 5);
+ objectStore.put({ bar: "B", baz: "b" }, 6);
+ objectStore.put({ bar: "B", baz: "b" }, 4);
+ objectStore.put({ bar: "C", baz: "c" }, 7);
+ objectStore.put({ bar: "C", baz: "c" }, 9);
+ objectStore.put({ bar: "C", baz: "c" }, 8);
+ objectStore.put({ bar: "D", baz: "d" }, 11);
+ objectStore.put({ bar: "D", baz: "d" }, 12);
+ objectStore.put({ bar: "D", baz: "d" }, 10);
+
+ var req = index.count();
+ req.onsuccess = function() {
+ log("TestIndex1 count is: " + req.result);
+ }
+
+ startNextCursor();
+
+ versionTransaction.onabort = function(event) {
+ log("Initial upgrade versionchange transaction unexpected aborted");
+ done();
+ }
+
+ versionTransaction.oncomplete = function(event) {
+ log("Initial upgrade versionchange transaction complete");
+ done();
+ }
+
+ versionTransaction.onerror = function(event) {
+ log("Initial upgrade versionchange transaction unexpected error" + event);
+ done();
+ }
+}
+
+</script>
</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.<br>
+<div id="logger"></div>
+<script>
+
+if (window.testRunner) {
+ testRunner.waitUntilDone();
+ testRunner.dumpAsText();
+}
+
+function done()
+{
+ log("Done");
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+function log(message)
+{
+ document.getElementById("logger").innerHTML += message + "<br>";
+}
+
+var index;
+var objectStore;
+
+function logCursor(cursor)
+{
+ log("Cursor direction is: " + cursor.direction);
+ log("Cursor source is: " + cursor.source.name);
+ log("Cursor key is: " + cursor.key);
+ log("Cursor primary key is: " + cursor.primaryKey);
+ log("Cursor value is: " + cursor.value);
+}
+
+function setupRequest(request)
+{
+ request.onsuccess = function() {
+ log("Success opening or iterating cursor");
+ logCursor(request.result);
+
+ if (request.iteratedOnce) {
+ var primaryKey = request.result.primaryKey;
+ if (primaryKey) {
+ objectStore.delete(primaryKey).onsuccess = function() {
+ log("Deleted key " + primaryKey + " from object store");
+ }
+ var nextPrimaryKey = primaryKey;
+ if (request.result.direction.startsWith("next")) {
+ nextPrimaryKey++;
+ if (nextPrimaryKey > 18)
+ nextPrimaryKey = 0;
+ } else
+ nextPrimaryKey--;
+
+ if (nextPrimaryKey > 0) {
+ objectStore.delete(nextPrimaryKey).onsuccess = function() {
+ log("Deleted key " + nextPrimaryKey + " from object store");
+ }
+ }
+
+ // 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("unique")) {
+ var nextNextPrimaryKey = nextPrimaryKey;
+ if (request.result.direction.startsWith("next")) {
+ nextNextPrimaryKey++;
+ if (nextNextPrimaryKey > 18)
+ nextNextPrimaryKey = 0;
+ } else
+ nextNextPrimaryKey--;
+
+ if (nextNextPrimaryKey > 0) {
+ objectStore.delete(nextNextPrimaryKey).onsuccess = function() {
+ log("Deleted key " + nextNextPrimaryKey + " from object store");
+ }
+ }
+ }
+ }
+ }
+
+ request.iteratedOnce = true;
+
+ if (request.result.key != undefined)
+ request.result.continue();
+ else
+ startNextCursor();
+ }
+ request.onerror = function(e) {
+ log("Unexpected error opening or iterating cursor");
+ logCursor(request.result);
+ done();
+ }
+}
+
+function testCursorDirection(index, direction)
+{
+ var range = IDBKeyRange.lowerBound(-Infinity);
+ var request = index.openCursor(range, direction);
+ setupRequest(request);
+}
+
+var cursorCommands = [
+ "testCursorDirection(index, 'prevunique')",
+ "testCursorDirection(index, 'nextunique')",
+ "testCursorDirection(index, 'prev')",
+ "testCursorDirection(index, 'next')",
+];
+
+function startNextCursor()
+{
+ if (!cursorCommands.length) {
+ done();
+ return;
+ }
+
+ populateObjectStore();
+
+ var command = cursorCommands.pop();
+ log("<br>Starting a new cursor: " + command);
+ var req = index.count();
+ req.onsuccess = function() {
+ log("<br>TestIndex1 count is: " + req.result + "<br>");
+ }
+
+ eval(command);
+}
+
+function populateObjectStore()
+{
+ objectStore.put({ bar: "A" }, 1);
+ objectStore.put({ bar: "A" }, 2);
+ objectStore.put({ bar: "B" }, 3);
+ objectStore.put({ bar: "B" }, 4);
+ objectStore.put({ bar: "C" }, 5);
+ objectStore.put({ bar: "C" }, 6);
+ objectStore.put({ bar: "D" }, 7);
+ objectStore.put({ bar: "D" }, 8);
+ objectStore.put({ bar: "E" }, 9);
+ objectStore.put({ bar: "E" }, 10);
+ objectStore.put({ bar: "F" }, 11);
+ objectStore.put({ bar: "F" }, 12);
+ objectStore.put({ bar: "G" }, 13);
+ objectStore.put({ bar: "G" }, 14);
+ objectStore.put({ bar: "H" }, 15);
+ objectStore.put({ bar: "H" }, 16);
+ objectStore.put({ bar: "I" }, 17);
+ objectStore.put({ bar: "I" }, 18);
+}
+
+var createRequest = window.indexedDB.open("IndexCursor3Database", 1);
+createRequest.onupgradeneeded = function(event) {
+ log("Initial upgrade needed: Old version - " + event.oldVersion + " New version - " + event.newVersion);
+
+ var versionTransaction = createRequest.transaction;
+ var database = event.target.result;
+ objectStore = database.createObjectStore("TestObjectStore");
+ index = objectStore.createIndex("TestIndex1", "bar");
+
+ startNextCursor();
+
+ versionTransaction.onabort = function(event) {
+ log("Initial upgrade versionchange transaction unexpected aborted");
+ done();
+ }
+
+ versionTransaction.oncomplete = function(event) {
+ log("Initial upgrade versionchange transaction complete");
+ done();
+ }
+
+ versionTransaction.onerror = function(event) {
+ log("Initial upgrade versionchange transaction unexpected error" + event);
+ done();
+ }
+}
+
+</script>
</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 <beidson@apple.com>
+
+ 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 <antti@apple.com>
</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->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->modernTransaction(), m_objectStore->info().identifier(), m_info.identifier(), rangeData, direction, IndexedDB::CursorType::KeyAndValue);
</ins><span class="cx"> Ref<IDBRequest> request = m_objectStore->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->modernTransaction(), m_info.identifier(), range, direction, IndexedDB::CursorType::KeyOnly);
</del><ins>+ auto info = IDBCursorInfo::indexCursor(m_objectStore->modernTransaction(), m_objectStore->info().identifier(), m_info.identifier(), range, direction, IndexedDB::CursorType::KeyOnly);
</ins><span class="cx"> Ref<IDBRequest> request = m_objectStore->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& key)
</span><span class="cx"> {
</span><del>- if (m_unique && m_key && *m_key == key) {
- delete m_key;
- m_key = nullptr;
- return true;
</del><ins>+ if (m_unique) {
+ if (m_key && *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->erase(key);
- return m_orderedKeys->empty();
</del><ins>+ return m_orderedKeys->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->size();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+IndexValueEntry::Iterator::Iterator(IndexValueEntry& entry)
+ : m_entry(&entry)
+{
+ ASSERT(m_entry->m_key);
+}
+
+IndexValueEntry::Iterator::Iterator(IndexValueEntry& entry, std::set<IDBKeyData>::iterator iterator)
+ : m_entry(&entry)
+ , m_forwardIterator(iterator)
+{
+}
+
+IndexValueEntry::Iterator::Iterator(IndexValueEntry& entry, std::set<IDBKeyData>::reverse_iterator iterator)
+ : m_entry(&entry)
+ , m_forward(false)
+ , m_reverseIterator(iterator)
+{
+}
+
+const IDBKeyData& IndexValueEntry::Iterator::key() const
+{
+ ASSERT(isValid());
+ if (m_entry->unique()) {
+ ASSERT(m_entry->m_key);
+ return *m_entry->m_key;
+ }
+
+ return m_forward ? *m_forwardIterator : *m_reverseIterator;
+}
+
+bool IndexValueEntry::Iterator::isValid() const
+{
+#ifndef NDEBUG
+ if (m_entry) {
+ if (m_entry->m_unique)
+ ASSERT(m_entry->m_key);
+ else
+ ASSERT(m_entry->m_orderedKeys);
+ }
+#endif
+
+ return m_entry;
+}
+
+void IndexValueEntry::Iterator::invalidate()
+{
+ m_entry = nullptr;
+}
+
+IndexValueEntry::Iterator& IndexValueEntry::Iterator::operator++()
+{
+ if (!isValid())
+ return *this;
+
+ if (m_entry->m_unique) {
+ invalidate();
+ return *this;
+ }
+
+ if (m_forward) {
+ ++m_forwardIterator;
+ if (m_forwardIterator == m_entry->m_orderedKeys->end())
+ invalidate();
+ } else {
+ ++m_reverseIterator;
+ if (m_reverseIterator == m_entry->m_orderedKeys->rend())
+ invalidate();
+ }
+
+ return *this;
+}
+
+IndexValueEntry::Iterator IndexValueEntry::begin()
+{
+ if (m_unique) {
+ ASSERT(m_key);
+ return { *this };
+ }
+
+ ASSERT(m_orderedKeys);
+ return { *this, m_orderedKeys->begin() };
+}
+
+IndexValueEntry::Iterator IndexValueEntry::reverseBegin()
+{
+ if (m_unique) {
+ ASSERT(m_key);
+ return { *this };
+ }
+
+ ASSERT(m_orderedKeys);
+ return { *this, m_orderedKeys->rbegin() };
+}
+
+IndexValueEntry::Iterator IndexValueEntry::find(const IDBKeyData& key)
+{
+ if (m_unique) {
+ ASSERT(m_key);
+ return *m_key == key ? IndexValueEntry::Iterator(*this) : IndexValueEntry::Iterator();
+ }
+
+ ASSERT(m_orderedKeys);
+ auto iterator = m_orderedKeys->lower_bound(key);
+ if (iterator == m_orderedKeys->end())
+ return { };
+
+ return { *this, iterator };
+}
+
+IndexValueEntry::Iterator IndexValueEntry::reverseFind(const IDBKeyData& key)
+{
+ if (m_unique) {
+ ASSERT(m_key);
+ return *m_key == key ? IndexValueEntry::Iterator(*this) : IndexValueEntry::Iterator();
+ }
+
+ ASSERT(m_orderedKeys);
+ auto iterator = std::set<IDBKeyData>::reverse_iterator(m_orderedKeys->upper_bound(key));
+ if (iterator == m_orderedKeys->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 <set>
</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&);
</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&);
</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&);
+ Iterator(IndexValueEntry&, std::set<IDBKeyData>::iterator);
+ Iterator(IndexValueEntry&, std::set<IDBKeyData>::reverse_iterator);
+
+ bool isValid() const;
+ void invalidate();
+
+ const IDBKeyData& key() const;
+ const ThreadSafeDataBuffer& value() const;
+
+ Iterator& operator++();
+
+ private:
+ IndexValueEntry* m_entry { nullptr };
+ bool m_forward { true };
+ std::set<IDBKeyData>::iterator m_forwardIterator;
+ std::set<IDBKeyData>::reverse_iterator m_reverseIterator;
+ };
+
+ Iterator begin();
+ Iterator reverseBegin();
+
+ // Finds the key, or the next higher record after the key.
+ Iterator find(const IDBKeyData&);
+ // Finds the key, or the next lowest record before the key.
+ Iterator reverseFind(const IDBKeyData&);
+
+ bool unique() const { return m_unique; }
+
</ins><span class="cx"> private:
</span><span class="cx"> union {
</span><span class="cx"> std::set<IDBKeyData>* 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 "IDBError.h"
</span><span class="cx"> #include "IDBKeyRangeData.h"
</span><ins>+#include "Logging.h"
+#include "MemoryIndex.h"
</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& valueKey)
</del><ins>+void IndexValueStore::removeEntriesWithValueKey(MemoryIndex& index, const IDBKeyData& valueKey)
</ins><span class="cx"> {
</span><span class="cx"> HashSet<IDBKeyData*> entryKeysToRemove;
</span><span class="cx">
</span><span class="cx"> for (auto& entry : m_records) {
</span><span class="cx"> if (entry.value->removeKey(valueKey))
</span><ins>+ index.notifyCursorsOfValueChange(entry.key, valueKey);
+ if (!entry.value->getCount())
</ins><span class="cx"> entryKeysToRemove.add(&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& range) const
</span><span class="cx"> {
</span><ins>+ LOG(IndexedDB, "IndexValueStore::lowestKeyWithRecordInRange - %s", 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<IDBKeyData>::iterator IndexValueStore::lowestIteratorInRange(const IDBKeyRangeData& 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 && *lowestInRange == range.lowerKey)
</del><ins>+ if (range.lowerOpen && *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->compare(range.upperKey) > 0)
</span><del>- return { };
</del><ins>+ return m_orderedKeys.end();
</ins><span class="cx"> if (range.upperOpen && *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<IDBKeyData>::reverse_iterator IndexValueStore::highestReverseIteratorInRange(const IDBKeyRangeData& range) const
+{
+ auto highestInRange = std::set<IDBKeyData>::reverse_iterator(m_orderedKeys.upper_bound(range.upperKey));
+
+ if (highestInRange == m_orderedKeys.rend())
+ return highestInRange;
+
+ if (range.upperOpen && *highestInRange == range.upperKey) {
+ ++highestInRange;
+
+ if (highestInRange == m_orderedKeys.rend())
+ return highestInRange;
+ }
+
+ if (!range.lowerKey.isNull()) {
+ if (highestInRange->compare(range.lowerKey) < 0)
+ return m_orderedKeys.rend();
+ if (range.lowerOpen && *highestInRange == range.lowerKey)
+ return m_orderedKeys.rend();
+ }
+
+ return highestInRange;
+}
+
+IndexValueStore::Iterator IndexValueStore::find(const IDBKeyData& 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->begin();
+ ASSERT(primaryIterator.isValid());
+ return { *this, iterator, primaryIterator };
+}
+
+IndexValueStore::Iterator IndexValueStore::find(const IDBKeyData& key, const IDBKeyData& 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->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->begin();
+ ASSERT(primaryIterator.isValid());
+
+ return { *this, iterator, primaryIterator };
+}
+
+IndexValueStore::Iterator IndexValueStore::reverseFind(const IDBKeyData& 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->reverseBegin();
+ ASSERT(primaryIterator.isValid());
+ return { *this, iterator, primaryIterator };
+}
+
+IndexValueStore::Iterator IndexValueStore::reverseFind(const IDBKeyData& key, const IDBKeyData& 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->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->reverseBegin();
+ ASSERT(primaryIterator.isValid());
+
+ return { *this, iterator, primaryIterator };
+}
+
+
+IndexValueStore::Iterator::Iterator(IndexValueStore& store, std::set<IDBKeyData>::iterator iterator, IndexValueEntry::Iterator primaryIterator)
+ : m_store(&store)
+ , m_forwardIterator(iterator)
+ , m_primaryKeyIterator(primaryIterator)
+{
+}
+
+IndexValueStore::Iterator::Iterator(IndexValueStore& store, std::set<IDBKeyData>::reverse_iterator iterator, IndexValueEntry::Iterator primaryIterator)
+ : m_store(&store)
+ , m_forward(false)
+ , m_reverseIterator(iterator)
+ , m_primaryKeyIterator(primaryIterator)
+{
+}
+
+IndexValueStore::Iterator& IndexValueStore::Iterator::nextIndexEntry()
+{
+ if (!m_store)
+ return *this;
+
+ if (m_forward) {
+ ++m_forwardIterator;
+ if (m_forwardIterator == m_store->m_orderedKeys.end()) {
+ invalidate();
+ return *this;
+ }
+
+ auto* entry = m_store->m_records.get(*m_forwardIterator);
+ ASSERT(entry);
+
+ m_primaryKeyIterator = entry->begin();
+ ASSERT(m_primaryKeyIterator.isValid());
+ } else {
+ ++m_reverseIterator;
+ if (m_reverseIterator == m_store->m_orderedKeys.rend()) {
+ invalidate();
+ return *this;
+ }
+
+ auto* entry = m_store->m_records.get(*m_reverseIterator);
+ ASSERT(entry);
+
+ m_primaryKeyIterator = entry->reverseBegin();
+ ASSERT(m_primaryKeyIterator.isValid());
+ }
+
+ return *this;
+}
+
+IndexValueStore::Iterator& 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 && m_primaryKeyIterator.isValid();
+}
+
+const IDBKeyData& IndexValueStore::Iterator::key()
+{
+ ASSERT(isValid());
+ return m_forward ? *m_forwardIterator : *m_reverseIterator;
+}
+
+const IDBKeyData& 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<IDBKeyData, std::unique_ptr<IndexValueEntry>, IDBKeyDataHash, IDBKeyDataHashTraits> 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& indexKey, const IDBKeyData& valueKey);
</span><span class="cx"> void removeRecord(const IDBKeyData& indexKey, const IDBKeyData& valueKey);
</span><span class="cx">
</span><del>- void removeEntriesWithValueKey(const IDBKeyData& valueKey);
</del><ins>+ void removeEntriesWithValueKey(MemoryIndex&, const IDBKeyData& valueKey);
</ins><span class="cx">
</span><ins>+ class Iterator {
+ friend class IndexValueStore;
+ public:
+ Iterator()
+ {
+ }
+
+ Iterator(IndexValueStore&, std::set<IDBKeyData>::iterator, IndexValueEntry::Iterator);
+ Iterator(IndexValueStore&, std::set<IDBKeyData>::reverse_iterator, IndexValueEntry::Iterator);
+
+ void invalidate();
+ bool isValid();
+
+ const IDBKeyData& key();
+ const IDBKeyData& primaryKey();
+ const ThreadSafeDataBuffer& value();
+
+ Iterator& operator++();
+ Iterator& nextIndexEntry();
+
+ private:
+ IndexValueStore* m_store { nullptr };
+ bool m_forward { true };
+ std::set<IDBKeyData>::iterator m_forwardIterator;
+ std::set<IDBKeyData>::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&, bool open = false);
+ Iterator reverseFind(const IDBKeyData&, 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&, const IDBKeyData& primaryKey);
+ Iterator reverseFind(const IDBKeyData&, const IDBKeyData& primaryKey);
+
</ins><span class="cx"> private:
</span><ins>+ std::set<IDBKeyData>::iterator lowestIteratorInRange(const IDBKeyRangeData&) const;
+ std::set<IDBKeyData>::reverse_iterator highestReverseIteratorInRange(const IDBKeyRangeData&) const;
+
</ins><span class="cx"> IndexKeyValueMap m_records;
</span><span class="cx"> std::set<IDBKeyData> 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("Index cursors not yet supported"));
</del><ins>+ auto* objectStore = m_objectStoresByIdentifier.get(info.objectStoreIdentifier());
+ if (!objectStore)
+ return IDBError(IDBExceptionCode::Unknown, ASCIILiteral("No backing store object store found"));
+
+ auto* index = objectStore->indexForIdentifier(info.sourceIdentifier());
+ if (!index)
+ return IDBError(IDBExceptionCode::Unknown, ASCIILiteral("No backing store index found"));
+
+ MemoryCursor* cursor = index->maybeOpenCursor(info);
+ if (!cursor)
+ return IDBError(IDBExceptionCode::Unknown, ASCIILiteral("Could not create index cursor in backing store"));
+
+ cursor->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& cursor)
+{
+ m_cleanCursors.add(&cursor);
+}
+
+void MemoryIndex::cursorDidBecomeDirty(MemoryIndexCursor& cursor)
+{
+ m_cleanCursors.remove(&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->indexCleared(*this, WTF::move(m_records));
</span><ins>+
+ notifyCursorsOfAllRecordsChanged();
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+void MemoryIndex::notifyCursorsOfValueChange(const IDBKeyData& indexKey, const IDBKeyData& primaryKey)
+{
+ Vector<MemoryIndexCursor*> cursors;
+ copyToVector(m_cleanCursors, cursors);
+ for (auto* cursor : cursors)
+ cursor->indexValueChanged(indexKey, primaryKey);
+}
+
+void MemoryIndex::notifyCursorsOfAllRecordsChanged()
+{
+ Vector<MemoryIndexCursor*> cursors;
+ copyToVector(m_cleanCursors, cursors);
+ for (auto* cursor : cursors)
+ cursor->indexRecordsAllChanged();
+
+ ASSERT(m_cleanCursors.isEmpty());
+}
+
</ins><span class="cx"> void MemoryIndex::replaceIndexValueStore(std::unique_ptr<IndexValueStore>&& 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, "MemoryIndex::provisionalPutIndexKey");
</span><span class="cx">
</span><del>- if (!m_records)
</del><ins>+ if (!m_records) {
</ins><span class="cx"> m_records = std::make_unique<IndexValueStore>(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->addRecord(key, valueKey);
</del><ins>+ IDBError result = m_records->addRecord(key, valueKey);
+ notifyCursorsOfValueChange(key, valueKey);
+ return result;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> Vector<IDBKeyData> keys = indexKey.multiEntry();
</span><span class="lines">@@ -142,6 +176,7 @@
</span><span class="cx"> for (auto& key : keys) {
</span><span class="cx"> auto error = m_records->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->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<IDBKeyData> keys = indexKey.multiEntry();
</span><del>- for (auto& key : keys)
</del><ins>+ for (auto& key : keys) {
</ins><span class="cx"> m_records->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& 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->removeEntriesWithValueKey(valueKey);
</del><ins>+ m_records->removeEntriesWithValueKey(*this, valueKey);
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+MemoryIndexCursor* MemoryIndex::maybeOpenCursor(const IDBCursorInfo& info)
+{
+ auto result = m_cursors.add(info.identifier(), nullptr);
+ if (!result.isNewEntry)
+ return nullptr;
+
+ result.iterator->value = std::make_unique<MemoryIndexCursor>(*this, info);
+ return result.iterator->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 "IDBIndexInfo.h"
</span><span class="cx"> #include "IDBKeyData.h"
</span><span class="cx"> #include "IndexValueStore.h"
</span><ins>+#include "MemoryIndexCursor.h"
</ins><span class="cx"> #include <set>
</span><span class="cx"> #include <wtf/HashMap.h>
</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<IndexValueStore>&&);
</span><span class="cx">
</span><ins>+ MemoryIndexCursor* maybeOpenCursor(const IDBCursorInfo&);
+
+ IndexValueStore* valueStore() { return m_records.get(); }
+
+ MemoryObjectStore& objectStore() { return m_objectStore; }
+
+ void cursorDidBecomeClean(MemoryIndexCursor&);
+ void cursorDidBecomeDirty(MemoryIndexCursor&);
+
+ void notifyCursorsOfValueChange(const IDBKeyData& indexKey, const IDBKeyData& primaryKey);
+
</ins><span class="cx"> private:
</span><span class="cx"> MemoryIndex(const IDBIndexInfo&, MemoryObjectStore&);
</span><span class="cx">
</span><span class="cx"> uint64_t recordCountForKey(const IDBKeyData&) const;
</span><del>-
</del><ins>+
+ void notifyCursorsOfAllRecordsChanged();
+
</ins><span class="cx"> IDBIndexInfo m_info;
</span><span class="cx"> MemoryObjectStore& m_objectStore;
</span><span class="cx">
</span><span class="cx"> std::unique_ptr<IndexValueStore> m_records;
</span><ins>+
+ HashMap<IDBResourceIdentifier, std::unique_ptr<MemoryIndexCursor>> m_cursors;
+ HashSet<MemoryIndexCursor*> 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 "config.h"
+#include "MemoryIndexCursor.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBCursorInfo.h"
+#include "IndexValueStore.h"
+#include "Logging.h"
+#include "MemoryCursor.h"
+#include "MemoryIndex.h"
+#include "MemoryObjectStore.h"
+
+namespace WebCore {
+namespace IDBServer {
+
+MemoryIndexCursor::MemoryIndexCursor(MemoryIndex& index, const IDBCursorInfo& info)
+ : MemoryCursor(info)
+ , m_index(index)
+{
+ auto* valueStore = m_index.valueStore();
+ if (!valueStore)
+ return;
+
+ IndexValueStore::Iterator iterator;
+ if (m_info.isDirectionForward())
+ iterator = valueStore->find(m_info.range().lowerKey, m_info.range().lowerOpen);
+ else
+ iterator = valueStore->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& 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& key, uint32_t count, IDBGetResult& getResult)
+{
+ LOG(IndexedDB, "MemoryIndexCursor::iterate to key %s, %u count", 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->find(m_currentKey);
+ else
+ m_currentIterator = valueStore->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 "1"
+ 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->find(m_currentKey, m_currentPrimaryKey);
+ break;
+ case IndexedDB::CursorDirection::NextNoDuplicate:
+ m_currentIterator = valueStore->find(m_currentKey, true);
+ break;
+ case IndexedDB::CursorDirection::Prev:
+ m_currentIterator = valueStore->reverseFind(m_currentKey, m_currentPrimaryKey);
+ break;
+ case IndexedDB::CursorDirection::PrevNoDuplicate:
+ m_currentIterator = valueStore->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() && !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& key, const IDBKeyData& 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 "IDBCursorInfo.h"
+#include "IndexValueStore.h"
+#include "MemoryCursor.h"
+
+namespace WebCore {
+namespace IDBServer {
+
+class MemoryIndex;
+
+class MemoryIndexCursor : public MemoryCursor {
+public:
+ MemoryIndexCursor(MemoryIndex&, const IDBCursorInfo&);
+ virtual ~MemoryIndexCursor();
+
+ void indexRecordsAllChanged();
+ void indexValueChanged(const IDBKeyData& indexKey, const IDBKeyData& primaryKey);
+
+private:
+ virtual void currentData(IDBGetResult&) override final;
+ virtual void iterate(const IDBKeyData&, uint32_t count, IDBGetResult&) override final;
+
+ MemoryIndex& 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& transaction)
</span><span class="cx"> {
</span><span class="cx"> LOG(IndexedDB, "MemoryObjectStore::writeTransactionStarted");
</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& key) const
+{
+ if (!m_keyValueStore)
+ return { };
+
+ return m_keyValueStore->get(key);
+}
+
</ins><span class="cx"> ThreadSafeDataBuffer MemoryObjectStore::valueForKeyRange(const IDBKeyRangeData& keyRangeData) const
</span><span class="cx"> {
</span><span class="cx"> LOG(IndexedDB, "MemoryObjectStore::valueForKey");
</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<KeyValueMap>&&, std::unique_ptr<std::set<IDBKeyData>>&&);
</span><span class="cx">
</span><ins>+ ThreadSafeDataBuffer valueForKey(const IDBKeyData&) const;
</ins><span class="cx"> ThreadSafeDataBuffer valueForKeyRange(const IDBKeyRangeData&) const;
</span><span class="cx"> IDBGetResult indexValueForKeyRange(uint64_t indexIdentifier, IndexedDB::IndexRecordType, const IDBKeyRangeData&) const;
</span><span class="cx"> uint64_t countForKeyRange(uint64_t indexIdentifier, const IDBKeyRangeData&) const;
</span><span class="lines">@@ -88,6 +89,8 @@
</span><span class="cx">
</span><span class="cx"> std::set<IDBKeyData>* 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&);
</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& transaction, uint64_t objectStoreIdentifier, const IDBKeyRangeData& 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& transaction, uint64_t indexIdentifier, const IDBKeyRangeData& range, IndexedDB::CursorDirection direction, IndexedDB::CursorType type)
</del><ins>+IDBCursorInfo IDBCursorInfo::indexCursor(IDBClient::IDBTransaction& transaction, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData& 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& transaction, IndexedDB::CursorSource source, uint64_t sourceIdentifier, const IDBKeyRangeData& range, IndexedDB::CursorDirection direction, IndexedDB::CursorType type)
</del><ins>+IDBCursorInfo::IDBCursorInfo(IDBClient::IDBTransaction& transaction, uint64_t objectStoreIdentifier, const IDBKeyRangeData& 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& cursorIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t sourceIdentifier, const IDBKeyRangeData& range, IndexedDB::CursorSource source, IndexedDB::CursorDirection direction, IndexedDB::CursorType type)
</del><ins>+IDBCursorInfo::IDBCursorInfo(IDBClient::IDBTransaction& transaction, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData& 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& cursorIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t sourceIdentifier, const IDBKeyRangeData& 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&, uint64_t objectStoreIdentifier, const IDBKeyRangeData&, IndexedDB::CursorDirection);
</span><del>- static IDBCursorInfo indexCursor(IDBClient::IDBTransaction&, uint64_t indexIdentifier, const IDBKeyRangeData&, IndexedDB::CursorDirection, IndexedDB::CursorType);
</del><ins>+ static IDBCursorInfo indexCursor(IDBClient::IDBTransaction&, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData&, 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& 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&, IndexedDB::CursorSource, uint64_t sourceIdentifier, const IDBKeyRangeData&, IndexedDB::CursorDirection, IndexedDB::CursorType);
- IDBCursorInfo(const IDBResourceIdentifier&, const IDBResourceIdentifier&, uint64_t, const IDBKeyRangeData&, IndexedDB::CursorSource, IndexedDB::CursorDirection, IndexedDB::CursorType);
</del><ins>+ IDBCursorInfo(IDBClient::IDBTransaction&, uint64_t objectStoreIdentifier, const IDBKeyRangeData&, IndexedDB::CursorDirection, IndexedDB::CursorType);
+ IDBCursorInfo(IDBClient::IDBTransaction&, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData&, IndexedDB::CursorDirection, IndexedDB::CursorType);
</ins><span class="cx">
</span><ins>+ IDBCursorInfo(const IDBResourceIdentifier&, const IDBResourceIdentifier&, uint64_t, uint64_t, const IDBKeyRangeData&, 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 = "<group>"; };
</span><span class="cx">                 518F97001BE94C5B0023187C /* MemoryIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryIndex.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 518F97011BE94C5B0023187C /* MemoryIndex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryIndex.h; sourceTree = "<group>"; };
</span><ins>+                519755F71BFD7DBC003DE980 /* MemoryIndexCursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryIndexCursor.cpp; sourceTree = "<group>"; };
+                519755F81BFD7DBC003DE980 /* MemoryIndexCursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryIndexCursor.h; sourceTree = "<group>"; };
</ins><span class="cx">                 5198F7A21BBDAA2900E2CC5F /* UniqueIDBDatabaseConnection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UniqueIDBDatabaseConnection.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 5198F7A31BBDAA2900E2CC5F /* UniqueIDBDatabaseConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UniqueIDBDatabaseConnection.h; sourceTree = "<group>"; };
</span><span class="cx">                 5198F7A61BBDD38100E2CC5F /* UniqueIDBDatabaseTransaction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UniqueIDBDatabaseTransaction.cpp; sourceTree = "<group>"; };
</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>