OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
55 this.element.addEventListener('scroll', this._onScroll.bind(this), false); | 55 this.element.addEventListener('scroll', this._onScroll.bind(this), false); |
56 this.element.addEventListener('copy', this._onCopy.bind(this), false); | 56 this.element.addEventListener('copy', this._onCopy.bind(this), false); |
57 this.element.addEventListener('dragstart', this._onDragStart.bind(this), fal se); | 57 this.element.addEventListener('dragstart', this._onDragStart.bind(this), fal se); |
58 | 58 |
59 this._firstActiveIndex = 0; | 59 this._firstActiveIndex = 0; |
60 this._lastActiveIndex = -1; | 60 this._lastActiveIndex = -1; |
61 this._renderedItems = []; | 61 this._renderedItems = []; |
62 this._anchorSelection = null; | 62 this._anchorSelection = null; |
63 this._headSelection = null; | 63 this._headSelection = null; |
64 this._itemCount = 0; | 64 this._itemCount = 0; |
65 this._cumulativeHeights = new Int32Array(0); | |
65 | 66 |
66 // Listen for any changes to descendants and trigger a refresh. This ensures | 67 // Listen for any changes to descendants and trigger a refresh. This ensures |
67 // that items updated asynchronously will not break stick-to-bottom behavior | 68 // that items updated asynchronously will not break stick-to-bottom behavior |
68 // if they change the scroll height. | 69 // if they change the scroll height. |
69 this._observer = new MutationObserver(this.refresh.bind(this)); | 70 this._observer = new MutationObserver(this.refresh.bind(this)); |
70 this._observerConfig = {childList: true, subtree: true}; | 71 this._observerConfig = {childList: true, subtree: true}; |
71 } | 72 } |
72 | 73 |
73 /** | 74 /** |
74 * @return {boolean} | 75 * @return {boolean} |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
113 } | 114 } |
114 | 115 |
115 /** | 116 /** |
116 * @return {!Element} | 117 * @return {!Element} |
117 */ | 118 */ |
118 contentElement() { | 119 contentElement() { |
119 return this._contentElement; | 120 return this._contentElement; |
120 } | 121 } |
121 | 122 |
122 invalidate() { | 123 invalidate() { |
123 delete this._cumulativeHeights; | |
124 delete this._cachedProviderElements; | 124 delete this._cachedProviderElements; |
125 this._itemCount = this._provider.itemCount(); | 125 this._itemCount = this._provider.itemCount(); |
126 this._rebuildCumulativeHeights(); | |
126 this.refresh(); | 127 this.refresh(); |
127 } | 128 } |
128 | 129 |
129 /** | 130 /** |
130 * @param {number} index | 131 * @param {number} index |
131 * @return {?Console.ConsoleViewportElement} | 132 * @return {?Console.ConsoleViewportElement} |
132 */ | 133 */ |
133 _providerElement(index) { | 134 _providerElement(index) { |
134 if (!this._cachedProviderElements) | 135 if (!this._cachedProviderElements) |
135 this._cachedProviderElements = new Array(this._itemCount); | 136 this._cachedProviderElements = new Array(this._itemCount); |
136 var element = this._cachedProviderElements[index]; | 137 var element = this._cachedProviderElements[index]; |
137 if (!element) { | 138 if (!element) { |
138 element = this._provider.itemElement(index); | 139 element = this._provider.itemElement(index); |
139 this._cachedProviderElements[index] = element; | 140 this._cachedProviderElements[index] = element; |
140 } | 141 } |
141 return element; | 142 return element; |
142 } | 143 } |
143 | 144 |
144 _rebuildCumulativeHeightsIfNeeded() { | 145 _rebuildCumulativeHeights() { |
145 if (this._cumulativeHeights) | 146 if (!this._itemCount) { |
dgozman
2017/04/07 20:31:44
I think this special-casing is not needed anymore.
luoe
2017/04/07 22:09:54
Done.
| |
147 this._cumulativeHeights = new Int32Array(0); | |
146 return; | 148 return; |
147 if (!this._itemCount) | 149 } |
148 return; | |
149 var firstActiveIndex = this._firstActiveIndex; | 150 var firstActiveIndex = this._firstActiveIndex; |
150 var lastActiveIndex = this._lastActiveIndex; | 151 var lastActiveIndex = this._lastActiveIndex; |
151 var height = 0; | 152 var height = 0; |
152 this._cumulativeHeights = new Int32Array(this._itemCount); | 153 this._cumulativeHeights = new Int32Array(this._itemCount); |
153 for (var i = 0; i < this._itemCount; ++i) { | 154 for (var i = 0; i < this._itemCount; ++i) { |
154 if (firstActiveIndex <= i && i <= lastActiveIndex) | 155 if (firstActiveIndex <= i && i <= lastActiveIndex) |
155 height += this._renderedItems[i - firstActiveIndex].element().offsetHeig ht; | 156 height += this._renderedItems[i - firstActiveIndex].element().offsetHeig ht; |
156 else | 157 else |
157 height += this._provider.fastHeight(i); | 158 height += this._provider.fastHeight(i); |
158 this._cumulativeHeights[i] = height; | 159 this._cumulativeHeights[i] = height; |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
317 } | 318 } |
318 | 319 |
319 var selection = this.element.getComponentSelection(); | 320 var selection = this.element.getComponentSelection(); |
320 var shouldRestoreSelection = this._updateSelectionModel(selection); | 321 var shouldRestoreSelection = this._updateSelectionModel(selection); |
321 | 322 |
322 var visibleFrom = this.element.scrollTop; | 323 var visibleFrom = this.element.scrollTop; |
323 var visibleHeight = this._visibleHeight(); | 324 var visibleHeight = this._visibleHeight(); |
324 | 325 |
325 for (var i = 0; i < this._renderedItems.length; ++i) { | 326 for (var i = 0; i < this._renderedItems.length; ++i) { |
326 // Tolerate 1-pixel error due to double-to-integer rounding errors. | 327 // Tolerate 1-pixel error due to double-to-integer rounding errors. |
327 if (this._cumulativeHeights && | 328 var cachedItemHeight = this._cachedItemHeight(this._firstActiveIndex + i); |
328 Math.abs(this._cachedItemHeight(this._firstActiveIndex + i) - this._re nderedItems[i].element().offsetHeight) > | 329 if (Math.abs(cachedItemHeight - this._renderedItems[i].element().offsetHei ght) > 1) { |
329 1) | 330 this._rebuildCumulativeHeights(); |
330 delete this._cumulativeHeights; | 331 break; |
332 } | |
331 } | 333 } |
332 this._rebuildCumulativeHeightsIfNeeded(); | |
333 var activeHeight = visibleHeight * 2; | 334 var activeHeight = visibleHeight * 2; |
334 // When the viewport is scrolled to the bottom, using the cumulative heights estimate is not | 335 // When the viewport is scrolled to the bottom, using the cumulative heights estimate is not |
335 // precise enough to determine next visible indices. This stickToBottom chec k avoids extra | 336 // precise enough to determine next visible indices. This stickToBottom chec k avoids extra |
336 // calls to refresh in those cases. | 337 // calls to refresh in those cases. |
337 if (this._stickToBottom) { | 338 if (this._stickToBottom) { |
338 this._firstActiveIndex = | 339 this._firstActiveIndex = |
339 Math.max(this._itemCount - Math.ceil(activeHeight / this._provider.min imumRowHeight()), 0); | 340 Math.max(this._itemCount - Math.ceil(activeHeight / this._provider.min imumRowHeight()), 0); |
340 this._lastActiveIndex = this._itemCount - 1; | 341 this._lastActiveIndex = this._itemCount - 1; |
341 } else { | 342 } else { |
342 this._firstActiveIndex = Math.max( | 343 this._firstActiveIndex = Math.max( |
343 Array.prototype.lowerBound.call( | 344 Int32Array.prototype.lowerBound.call( |
344 this._cumulativeHeights, visibleFrom + 1 - (activeHeight - visible Height) / 2), | 345 this._cumulativeHeights, visibleFrom + 1 - (activeHeight - visible Height) / 2), |
345 0); | 346 0); |
346 // Proactively render more rows in case some of them will be collapsed wit hout triggering refresh. @see crbug.com/390169 | 347 // Proactively render more rows in case some of them will be collapsed wit hout triggering refresh. @see crbug.com/390169 |
347 this._lastActiveIndex = this._firstActiveIndex + Math.ceil(activeHeight / this._provider.minimumRowHeight()) - 1; | 348 this._lastActiveIndex = this._firstActiveIndex + Math.ceil(activeHeight / this._provider.minimumRowHeight()) - 1; |
348 this._lastActiveIndex = Math.min(this._lastActiveIndex, this._itemCount - 1); | 349 this._lastActiveIndex = Math.min(this._lastActiveIndex, this._itemCount - 1); |
349 } | 350 } |
350 | 351 |
351 var topGapHeight = this._cumulativeHeights[this._firstActiveIndex - 1] || 0; | 352 var topGapHeight = this._cumulativeHeights[this._firstActiveIndex - 1] || 0; |
352 var bottomGapHeight = | 353 var bottomGapHeight = |
353 this._cumulativeHeights[this._cumulativeHeights.length - 1] - this._cumu lativeHeights[this._lastActiveIndex]; | 354 this._cumulativeHeights[this._cumulativeHeights.length - 1] - this._cumu lativeHeights[this._lastActiveIndex]; |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
468 */ | 469 */ |
469 _onScroll(event) { | 470 _onScroll(event) { |
470 this.refresh(); | 471 this.refresh(); |
471 } | 472 } |
472 | 473 |
473 /** | 474 /** |
474 * @return {number} | 475 * @return {number} |
475 */ | 476 */ |
476 firstVisibleIndex() { | 477 firstVisibleIndex() { |
477 var firstVisibleIndex = | 478 var firstVisibleIndex = |
478 Math.max(Array.prototype.lowerBound.call(this._cumulativeHeights, this.e lement.scrollTop + 1), 0); | 479 Math.max(Int32Array.prototype.lowerBound.call(this._cumulativeHeights, t his.element.scrollTop + 1), 0); |
479 return Math.max(firstVisibleIndex, this._firstActiveIndex); | 480 return Math.max(firstVisibleIndex, this._firstActiveIndex); |
480 } | 481 } |
481 | 482 |
482 /** | 483 /** |
483 * @return {number} | 484 * @return {number} |
484 */ | 485 */ |
485 lastVisibleIndex() { | 486 lastVisibleIndex() { |
486 var lastVisibleIndex; | 487 var lastVisibleIndex; |
487 if (this._stickToBottom) { | 488 if (this._stickToBottom) { |
488 lastVisibleIndex = this._itemCount - 1; | 489 lastVisibleIndex = this._itemCount - 1; |
(...skipping 30 matching lines...) Expand all Loading... | |
519 this.forceScrollItemToBeFirst(index); | 520 this.forceScrollItemToBeFirst(index); |
520 else if (index >= lastVisibleIndex) | 521 else if (index >= lastVisibleIndex) |
521 this.forceScrollItemToBeLast(index); | 522 this.forceScrollItemToBeLast(index); |
522 } | 523 } |
523 | 524 |
524 /** | 525 /** |
525 * @param {number} index | 526 * @param {number} index |
526 */ | 527 */ |
527 forceScrollItemToBeFirst(index) { | 528 forceScrollItemToBeFirst(index) { |
528 this.setStickToBottom(false); | 529 this.setStickToBottom(false); |
529 this._rebuildCumulativeHeightsIfNeeded(); | |
530 this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0; | 530 this.element.scrollTop = index > 0 ? this._cumulativeHeights[index - 1] : 0; |
531 if (this.element.isScrolledToBottom()) | 531 if (this.element.isScrolledToBottom()) |
532 this.setStickToBottom(true); | 532 this.setStickToBottom(true); |
533 this.refresh(); | 533 this.refresh(); |
534 } | 534 } |
535 | 535 |
536 /** | 536 /** |
537 * @param {number} index | 537 * @param {number} index |
538 */ | 538 */ |
539 forceScrollItemToBeLast(index) { | 539 forceScrollItemToBeLast(index) { |
540 this.setStickToBottom(false); | 540 this.setStickToBottom(false); |
541 this._rebuildCumulativeHeightsIfNeeded(); | |
luoe
2017/04/07 01:19:38
By default, CH is an empty typed array if there ar
| |
542 this.element.scrollTop = this._cumulativeHeights[index] - this._visibleHeigh t(); | 541 this.element.scrollTop = this._cumulativeHeights[index] - this._visibleHeigh t(); |
543 if (this.element.isScrolledToBottom()) | 542 if (this.element.isScrolledToBottom()) |
544 this.setStickToBottom(true); | 543 this.setStickToBottom(true); |
545 this.refresh(); | 544 this.refresh(); |
546 } | 545 } |
547 | 546 |
548 /** | 547 /** |
549 * @return {number} | 548 * @return {number} |
550 */ | 549 */ |
551 _visibleHeight() { | 550 _visibleHeight() { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
598 Console.ConsoleViewportElement.prototype = { | 597 Console.ConsoleViewportElement.prototype = { |
599 willHide() {}, | 598 willHide() {}, |
600 | 599 |
601 wasShown() {}, | 600 wasShown() {}, |
602 | 601 |
603 /** | 602 /** |
604 * @return {!Element} | 603 * @return {!Element} |
605 */ | 604 */ |
606 element() {}, | 605 element() {}, |
607 }; | 606 }; |
OLD | NEW |