1/* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import {TransformMatrix} from 'common/geometry/transform_matrix'; 18import {UiRectBuilder} from 'viewers/components/rects/ui_rect_builder'; 19import {RectFilter} from './rect_filter'; 20import {RectShowState} from './rect_show_state'; 21 22describe('RectFilter', () => { 23 let rectFilter: RectFilter; 24 const nonVisibleNoContentRect = makeRect( 25 'nonVisibleNoContentRect', 26 false, 27 false, 28 ); 29 const nonVisibleContentRect = makeRect('nonVisibleContentRect', false, true); 30 const visibleContentRect = makeRect('visibleContentRect', true, true); 31 const visibleNoContentRect = makeRect('visibleNoContentRect', true, false); 32 const displayRect = makeRect('displayRect', false, false, true); 33 const allRects = [ 34 visibleContentRect, 35 visibleNoContentRect, 36 nonVisibleContentRect, 37 nonVisibleNoContentRect, 38 displayRect, 39 ]; 40 const preFilteredRects = [ 41 visibleContentRect, 42 visibleNoContentRect, 43 nonVisibleContentRect, 44 nonVisibleNoContentRect, 45 ]; 46 let expectedRectIdToShowState: Map<string, RectShowState>; 47 48 beforeEach(() => { 49 rectFilter = new RectFilter((id: string) => id); 50 expectedRectIdToShowState = new Map([ 51 [visibleContentRect.id, RectShowState.SHOW], 52 [visibleNoContentRect.id, RectShowState.SHOW], 53 [nonVisibleContentRect.id, RectShowState.SHOW], 54 [nonVisibleNoContentRect.id, RectShowState.SHOW], 55 [displayRect.id, RectShowState.SHOW], 56 ]); 57 }); 58 59 it('creates rect id to show state map', () => { 60 expect(rectFilter.getRectIdToShowState(allRects, allRects)).toEqual( 61 expectedRectIdToShowState, 62 ); 63 64 // sets hide state for rect that is not present in filtered rects 65 expectedRectIdToShowState.set(displayRect.id, RectShowState.HIDE); 66 expect(rectFilter.getRectIdToShowState(allRects, preFilteredRects)).toEqual( 67 expectedRectIdToShowState, 68 ); 69 70 // keeps rect that is not present in drawn rects but has force-show state 71 rectFilter.updateRectShowState(displayRect.id, RectShowState.SHOW); 72 expectedRectIdToShowState.set(displayRect.id, RectShowState.SHOW); 73 expect(rectFilter.getRectIdToShowState(allRects, preFilteredRects)).toEqual( 74 expectedRectIdToShowState, 75 ); 76 }); 77 78 it('updates rect forced show state', () => { 79 expect(isShown(visibleContentRect.id)).toBeTrue(); 80 81 // robust to same state (RectShowState.SHOW) 82 rectFilter.updateRectShowState(visibleContentRect.id, RectShowState.SHOW); 83 expect(isShown(visibleContentRect.id)).toBeTrue(); 84 85 rectFilter.updateRectShowState(visibleContentRect.id, RectShowState.HIDE); 86 expect(isShown(visibleContentRect.id)).toBeFalse(); 87 88 // robust to same state (RectShowState.HIDE) 89 rectFilter.updateRectShowState(visibleContentRect.id, RectShowState.HIDE); 90 expect(isShown(visibleContentRect.id)).toBeFalse(); 91 92 rectFilter.updateRectShowState(visibleContentRect.id, RectShowState.SHOW); 93 expect(isShown(visibleContentRect.id)).toBeTrue(); 94 95 expect(isShown(displayRect.id)).toBeFalse(); 96 rectFilter.updateRectShowState(displayRect.id, RectShowState.SHOW); 97 expect(isShown(displayRect.id)).toBeTrue(); 98 }); 99 100 it('does not filter rects if applicable', () => { 101 expect(rectFilter.filterRects(allRects, false, true, false)).toEqual( 102 allRects, 103 ); 104 }); 105 106 it('filters non visible rects', () => { 107 const filteredRects = rectFilter.filterRects(allRects, true, true, false); 108 expect(filteredRects).toEqual([ 109 visibleContentRect, 110 visibleNoContentRect, 111 displayRect, 112 ]); 113 114 // robust to all visible rects 115 expect(rectFilter.filterRects(filteredRects, true, true, false)).toEqual( 116 filteredRects, 117 ); 118 119 // does not apply force-hide state 120 rectFilter.updateRectShowState(visibleContentRect.id, RectShowState.HIDE); 121 expect(rectFilter.filterRects(allRects, true, true, false)).toEqual( 122 filteredRects, 123 ); 124 125 // does not apply force-show state 126 rectFilter.updateRectShowState( 127 nonVisibleContentRect.id, 128 RectShowState.SHOW, 129 ); 130 expect(rectFilter.filterRects(allRects, true, true, false)).toEqual( 131 filteredRects, 132 ); 133 }); 134 135 it('applies show/hide states', () => { 136 rectFilter.updateRectShowState(visibleContentRect.id, RectShowState.HIDE); 137 const filteredRects = rectFilter.filterRects(allRects, false, false, false); 138 expect(filteredRects).toEqual([ 139 visibleNoContentRect, 140 nonVisibleContentRect, 141 nonVisibleNoContentRect, 142 displayRect, 143 ]); 144 145 // robust to no change in show/hide states 146 expect(rectFilter.filterRects(filteredRects, false, false, false)).toEqual( 147 filteredRects, 148 ); 149 150 rectFilter.updateRectShowState(visibleContentRect.id, RectShowState.SHOW); 151 expect(rectFilter.filterRects(allRects, false, false, false)).toEqual( 152 allRects, 153 ); 154 }); 155 156 it('filters non visible rects and applies show/hide states', () => { 157 // does not remove force-shown non-visible rect 158 rectFilter.updateRectShowState( 159 nonVisibleContentRect.id, 160 RectShowState.SHOW, 161 ); 162 rectFilter.updateRectShowState( 163 nonVisibleNoContentRect.id, 164 RectShowState.SHOW, 165 ); 166 expect(rectFilter.filterRects(allRects, true, false, false)).toEqual( 167 allRects, 168 ); 169 170 // removes force-hidden visible rect 171 rectFilter.updateRectShowState(visibleContentRect.id, RectShowState.HIDE); 172 const filteredRects = rectFilter.filterRects(allRects, true, false, false); 173 expect(filteredRects).toEqual([ 174 visibleNoContentRect, 175 nonVisibleContentRect, 176 nonVisibleNoContentRect, 177 displayRect, 178 ]); 179 180 // removes non-visible rect but keeps visible rect that has not had hide/show state applied 181 rectFilter.updateRectShowState( 182 nonVisibleNoContentRect.id, 183 RectShowState.HIDE, 184 ); 185 expect(rectFilter.filterRects(allRects, true, false, false)).toEqual([ 186 visibleNoContentRect, 187 nonVisibleContentRect, 188 displayRect, 189 ]); 190 }); 191 192 it('filters rects without content', () => { 193 const filteredRects = rectFilter.filterRects(allRects, false, true, true); 194 expect(filteredRects).toEqual([ 195 visibleContentRect, 196 nonVisibleContentRect, 197 displayRect, 198 ]); 199 200 // robust to all rects with content 201 expect(rectFilter.filterRects(filteredRects, false, true, true)).toEqual( 202 filteredRects, 203 ); 204 }); 205 206 it('filters rects without content by show state and visibility', () => { 207 const filteredRects = rectFilter.filterRects(allRects, true, false, true); 208 expect(filteredRects).toEqual([visibleContentRect, displayRect]); 209 210 // does not apply force-hide state 211 rectFilter.updateRectShowState(visibleContentRect.id, RectShowState.HIDE); 212 expect(rectFilter.filterRects(allRects, true, true, true)).toEqual( 213 filteredRects, 214 ); 215 216 // does not apply force-show state 217 rectFilter.updateRectShowState( 218 nonVisibleNoContentRect.id, 219 RectShowState.SHOW, 220 ); 221 expect(rectFilter.filterRects(allRects, true, true, true)).toEqual( 222 filteredRects, 223 ); 224 }); 225 226 it('applies forced state key callback', () => { 227 const relaxedRectFilter = new RectFilter((id) => 228 id.slice(id.length - 5, id.length - 1), 229 ); 230 relaxedRectFilter.updateRectShowState('TestRect', RectShowState.HIDE); 231 expect( 232 relaxedRectFilter.filterRects(allRects, false, false, false), 233 ).toEqual([displayRect]); 234 }); 235 236 function isShown(rectId: string) { 237 const nonHiddenRectIds = rectFilter.getRectIdToShowState( 238 allRects, 239 preFilteredRects, 240 ); 241 return nonHiddenRectIds.get(rectId) === RectShowState.SHOW; 242 } 243 244 function makeRect( 245 id: string, 246 isVisible: boolean, 247 hasContent: boolean, 248 isDisplay = false, 249 ) { 250 return new UiRectBuilder() 251 .setX(0) 252 .setY(0) 253 .setWidth(1) 254 .setHeight(1) 255 .setLabel(id) 256 .setTransform( 257 TransformMatrix.from({ 258 dsdx: 1, 259 dsdy: 0, 260 dtdx: 0, 261 dtdy: 1, 262 tx: 0, 263 ty: 0, 264 }), 265 ) 266 .setIsVisible(isVisible) 267 .setIsDisplay(isDisplay) 268 .setIsActiveDisplay(false) 269 .setId(id) 270 .setGroupId(0) 271 .setIsClickable(false) 272 .setCornerRadius(0) 273 .setDepth(0) 274 .setOpacity(0.5) 275 .setHasContent(hasContent) 276 .build(); 277 } 278}); 279