Merge changes I65790d0b,I01c26655

* changes:
  Add support for configurable performance metrics
  PerformanceLogger: Dropped the deprecated methods
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 6b7f1f0..9f7b763 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -414,7 +414,6 @@
   private final DynamicSet<PerformanceLogger> performanceLoggers;
   private final PermissionBackend permissionBackend;
   private final ProjectCache projectCache;
-  private final Provider<InternalChangeQuery> queryProvider;
   private final Provider<MergeOp> mergeOpProvider;
   private final Provider<MergeOpRepoManager> ormProvider;
   private final ReceiveConfig receiveConfig;
@@ -505,7 +504,6 @@
       DynamicSet<PerformanceLogger> performanceLoggers,
       PermissionBackend permissionBackend,
       ProjectCache projectCache,
-      Provider<InternalChangeQuery> queryProvider,
       Provider<MergeOp> mergeOpProvider,
       Provider<MergeOpRepoManager> ormProvider,
       PublishCommentsOp.Factory publishCommentsOp,
@@ -568,7 +566,6 @@
     this.psUtil = psUtil;
     this.performanceLoggers = performanceLoggers;
     this.publishCommentsOp = publishCommentsOp;
-    this.queryProvider = queryProvider;
     this.receiveConfig = receiveConfig;
     this.refValidatorsFactory = refValidatorsFactory;
     this.replaceOpFactory = replaceOpFactory;
@@ -2931,18 +2928,27 @@
 
   private ChangeLookup lookupByChangeKey(RevCommit c, Change.Key key) {
     try (TraceTimer traceTimer = newTimer("lookupByChangeKey")) {
-      List<ChangeData> byBranchKeyExactMatch =
-          queryProvider.get().byBranchKey(magicBranch.dest, key).stream()
-              .filter(cd -> cd.change().getKey().equals(key))
-              .collect(toList());
-      return new ChangeLookup(c, key, byBranchKeyExactMatch);
+      List<ChangeData> byBranchKey =
+          retryHelper
+              .changeIndexQuery(
+                  "lookupByChangeKey",
+                  q ->
+                      q.byBranchKey(magicBranch.dest, key).stream()
+                          .filter(cd -> cd.change().getKey().equals(key))
+                          .collect(toList()))
+              .call();
+      return new ChangeLookup(c, key, byBranchKey);
     }
   }
 
   private ChangeLookup lookupByCommit(RevCommit c) {
     try (TraceTimer traceTimer = newTimer("lookupByCommit")) {
-      return new ChangeLookup(
-          c, null, queryProvider.get().byBranchCommit(magicBranch.dest, c.getName()));
+      List<ChangeData> byBranchCommit =
+          retryHelper
+              .changeIndexQuery(
+                  "lookupByCommit", q -> q.byBranchCommit(magicBranch.dest, c.getName()))
+              .call();
+      return new ChangeLookup(c, null, byBranchCommit);
     }
   }
 
diff --git a/java/com/google/gerrit/server/restapi/change/SuggestReviewers.java b/java/com/google/gerrit/server/restapi/change/SuggestReviewers.java
index 0035a03..b09ce21 100644
--- a/java/com/google/gerrit/server/restapi/change/SuggestReviewers.java
+++ b/java/com/google/gerrit/server/restapi/change/SuggestReviewers.java
@@ -29,9 +29,9 @@
 public class SuggestReviewers {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
-  private static final int DEFAULT_MAX_SUGGESTED = 10;
+  public static final boolean DEFAULT_SKIP_SERVICE_USERS = true;
 
-  private static final boolean DEFAULT_SKIP_SERVICE_USERS = true;
+  private static final int DEFAULT_MAX_SUGGESTED = 10;
 
   protected final ReviewersUtil reviewersUtil;
 
diff --git a/modules/jgit b/modules/jgit
index 76ce6d9..cfdfb01 160000
--- a/modules/jgit
+++ b/modules/jgit
@@ -1 +1 @@
-Subproject commit 76ce6d91a2e07fdfcbfc8df6970c9e98a98e36a0
+Subproject commit cfdfb01f4c7de1d61a4913deac1d02837b53df82
diff --git a/polygerrit-ui/app/api/diff.ts b/polygerrit-ui/app/api/diff.ts
index 24110ed..90cf17b 100644
--- a/polygerrit-ui/app/api/diff.ts
+++ b/polygerrit-ui/app/api/diff.ts
@@ -552,3 +552,13 @@
     intentionalMove?: boolean
   ): void;
 }
+
+/**
+ * Represents a list of ranges in a diff that should be focused.
+ *
+ * This is used to collapse diff chunks that are not in focus.
+ */
+export declare interface DiffRangesToFocus {
+  left: {start: number; end: number}[];
+  right: {start: number; end: number}[];
+}
diff --git a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts
index e1fc2ed..1ec5262e 100644
--- a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts
+++ b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts
@@ -271,6 +271,16 @@
         .breadcrumbTooltip {
           white-space: nowrap;
         }
+        .unrelatedChanges {
+          color: var(--primary-button-text-color);
+          background-color: var(--primary-button-background-color);
+
+          &:hover {
+            // TODO(anuragpathak): Update hover colors as per specification.
+            color: var(--primary-button-text-color);
+            background-color: var(--primary-button-background-color);
+          }
+        }
       `,
     ];
   }
@@ -370,8 +380,14 @@
     let classes = 'contextControlButton showContext ';
 
     if (type === ContextButtonType.ALL) {
-      text = `+${pluralize(linesToExpand, 'common line')}`;
-      ariaLabel = `Show ${pluralize(linesToExpand, 'common line')}`;
+      if (this.group.hasNonCommonDeltaGroup()) {
+        text = '+ Unrelated changes';
+        ariaLabel = 'Show unrelated changes';
+        classes += ' unrelatedChanges ';
+      } else {
+        text = `+${pluralize(linesToExpand, 'common line')}`;
+        ariaLabel = `Show ${pluralize(linesToExpand, 'common line')}`;
+      }
       classes += this.showBoth()
         ? 'centeredButton'
         : this.showAbove()
@@ -483,7 +499,7 @@
    * Creates a container div with partial (+10) expansion buttons (above and/or below).
    */
   private createPartialExpansionButtons() {
-    if (!this.showPartialLinks()) {
+    if (!this.showPartialLinks() || this.group?.hasNonCommonDeltaGroup()) {
       return undefined;
     }
     let aboveButton;
@@ -515,7 +531,8 @@
     if (
       !this.showPartialLinks() ||
       !this.renderPreferences?.use_block_expansion ||
-      this.group?.hasSkipGroup()
+      this.group?.hasSkipGroup() ||
+      this.group?.hasNonCommonDeltaGroup()
     ) {
       return undefined;
     }
diff --git a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls_test.ts b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls_test.ts
index 20fc9c4..74726bf 100644
--- a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls_test.ts
@@ -10,7 +10,10 @@
 import {SyntaxBlock} from '../../../api/diff';
 import {fixture, html, assert} from '@open-wc/testing';
 import {waitEventLoop} from '../../../test/test-utils';
-import {createContextGroup} from '../../../test/test-data-generators';
+import {
+  createContextGroup,
+  createContextGroupWithDelta,
+} from '../../../test/test-data-generators';
 
 suite('gr-context-control tests', () => {
   let element: GrContextControls;
@@ -333,4 +336,16 @@
     assert.equal(tooltipAbove.getAttribute('position'), 'top');
     assert.equal(tooltipBelow.getAttribute('position'), 'bottom');
   });
+
+  test('context control with delta group', async () => {
+    element.group = createContextGroupWithDelta();
+    await waitEventLoop();
+
+    const buttons = element.shadowRoot!.querySelectorAll(
+      'paper-button.showContext'
+    );
+    assert.equal(buttons.length, 1);
+    assert.equal(buttons[0].textContent!.trim(), '+ Unrelated changes');
+    assert.include([...buttons[0].classList.values()], 'unrelatedChanges');
+  });
 });
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-model/gr-diff-model.ts b/polygerrit-ui/app/embed/diff/gr-diff-model/gr-diff-model.ts
index 88451f6..8488bd5 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-model/gr-diff-model.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-model/gr-diff-model.ts
@@ -10,6 +10,7 @@
   DiffInfo,
   DiffLayer,
   DiffPreferencesInfo,
+  DiffRangesToFocus,
   DiffResponsiveMode,
   DiffViewMode,
   DisplayLine,
@@ -51,6 +52,7 @@
   renderPrefs: RenderPreferences;
   diffPrefs: DiffPreferencesInfo;
   lineOfInterest?: DisplayLine;
+  diffRangesToFocus?: DiffRangesToFocus;
   comments: GrDiffCommentThread[];
   groups: GrDiffGroup[];
   /** how much context to show for large files */
@@ -211,6 +213,9 @@
       computeKeyLocations(diffState.lineOfInterest, diffState.comments ?? [])
   );
 
+  readonly diffRangesToFocus$: Observable<DiffRangesToFocus | undefined> =
+    select(this.state$, diffState => diffState.diffRangesToFocus);
+
   constructor(
     /**
      * Normally a reference to the <gr-diff> component. Used for firing events
@@ -232,23 +237,31 @@
   }
 
   processDiff() {
-    return combineLatest([this.diff$, this.context$, this.renderPrefs$])
+    return combineLatest([
+      this.diff$,
+      this.context$,
+      this.renderPrefs$,
+      this.diffRangesToFocus$,
+    ])
       .pipe(
         withLatestFrom(this.keyLocations$),
         debounceTime(1),
-        map(([[diff, context, renderPrefs], keyLocations]) => {
-          const options: ProcessingOptions = {
-            context,
-            keyLocations,
-            isBinary: !!(isImageDiff(diff) || diff.binary),
-          };
-          if (renderPrefs?.num_lines_rendered_at_once) {
-            options.asyncThreshold = renderPrefs.num_lines_rendered_at_once;
-          }
+        map(
+          ([[diff, context, renderPrefs, diffRangesToFocus], keyLocations]) => {
+            const options: ProcessingOptions = {
+              context,
+              keyLocations,
+              isBinary: !!(isImageDiff(diff) || diff.binary),
+              diffRangesToFocus,
+            };
+            if (renderPrefs?.num_lines_rendered_at_once) {
+              options.asyncThreshold = renderPrefs.num_lines_rendered_at_once;
+            }
 
-          const processor = new GrDiffProcessor(options);
-          return processor.process(diff.content);
-        })
+            const processor = new GrDiffProcessor(options);
+            return processor.process(diff.content);
+          }
+        )
       )
       .subscribe(groups => {
         this.updateState({groups});
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts b/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts
index 6b7b45f..1561dad 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts
@@ -9,7 +9,7 @@
   GrDiffGroupType,
   hideInContextControl,
 } from '../gr-diff/gr-diff-group';
-import {DiffContent} from '../../../types/diff';
+import {DiffContent, DiffRangesToFocus} from '../../../types/diff';
 import {Side} from '../../../constants/constants';
 import {getStringLength} from '../gr-diff-highlight/gr-annotation';
 import {GrDiffLineType, LineNumber} from '../../../api/diff';
@@ -41,6 +41,7 @@
   keyLocations?: KeyLocations;
   asyncThreshold?: number;
   isBinary?: boolean;
+  diffRangesToFocus?: DiffRangesToFocus;
 }
 
 /**
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-group.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-group.ts
index c5366e7..c7e9f44 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-group.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-group.ts
@@ -165,7 +165,8 @@
  * Groups where all lines are before or all lines are after the split will be
  * retained as is and put into the first or second list respectively. Groups
  * with some lines before and some lines after the split will be split into
- * two groups, which will be put into the first and second list.
+ * two groups, which will be put into the first and second list. Groups with
+ * type DELTA which are not common will not be split.
  *
  * @param split A line number offset relative to the first group's
  *     start line at which the groups should be split.
@@ -179,31 +180,41 @@
   if (groups.length === 0) return [[], []];
   const leftSplit = groups[0].lineRange.left.start_line + split;
   const rightSplit = groups[0].lineRange.right.start_line + split;
-
+  let isSplitDone = false;
   const beforeGroups = [];
   const afterGroups = [];
   for (const group of groups) {
-    const isCompletelyBefore =
-      group.lineRange.left.end_line < leftSplit ||
-      group.lineRange.right.end_line < rightSplit;
-    const isCompletelyAfter =
-      leftSplit <= group.lineRange.left.start_line ||
-      rightSplit <= group.lineRange.right.start_line;
-    if (isCompletelyBefore) {
-      beforeGroups.push(group);
-    } else if (isCompletelyAfter) {
+    if (isSplitDone) {
       afterGroups.push(group);
+    } else if (
+      group.type === GrDiffGroupType.DELTA &&
+      !group.ignoredWhitespaceOnly
+    ) {
+      beforeGroups.push(group);
     } else {
-      const {beforeSplit, afterSplit} = splitGroupInTwo(
-        group,
-        leftSplit,
-        rightSplit
-      );
-      if (beforeSplit) {
-        beforeGroups.push(beforeSplit);
-      }
-      if (afterSplit) {
-        afterGroups.push(afterSplit);
+      const isCompletelyBefore =
+        group.lineRange.left.end_line < leftSplit ||
+        group.lineRange.right.end_line < rightSplit;
+      const isCompletelyAfter =
+        leftSplit <= group.lineRange.left.start_line ||
+        rightSplit <= group.lineRange.right.start_line;
+      if (isCompletelyBefore) {
+        beforeGroups.push(group);
+      } else if (isCompletelyAfter) {
+        afterGroups.push(group);
+      } else {
+        const {beforeSplit, afterSplit} = splitGroupInTwo(
+          group,
+          leftSplit,
+          rightSplit
+        );
+        if (beforeSplit) {
+          beforeGroups.push(beforeSplit);
+        }
+        if (afterSplit) {
+          afterGroups.push(afterSplit);
+        }
+        isSplitDone = true;
       }
     }
   }
@@ -438,6 +449,15 @@
     );
   }
 
+  /** Returns true if it contains a DELTA group excluding whitespace only
+   * changes.
+   */
+  hasNonCommonDeltaGroup() {
+    return this.contextGroups?.some(
+      g => g.type === GrDiffGroupType.DELTA && !g.ignoredWhitespaceOnly
+    );
+  }
+
   containsLine(side: Side, line: LineNumber) {
     if (typeof line !== 'number') {
       // For FILE and LOST, beforeNumber and afterNumber are the same
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-group_test.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-group_test.ts
index bbbb4ad..c8446f0 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-group_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-group_test.ts
@@ -97,6 +97,8 @@
 
   suite('hideInContextControl', () => {
     let groups: GrDiffGroup[];
+    let groupsWithDelta: GrDiffGroup[];
+    let groupsWithWhiteSpaceOnlyChange: GrDiffGroup[];
     setup(() => {
       groups = [
         new GrDiffGroup({
@@ -108,6 +110,46 @@
           ],
         }),
         new GrDiffGroup({
+          type: GrDiffGroupType.BOTH,
+          lines: [
+            new GrDiffLine(GrDiffLineType.BOTH, 8, 10),
+            new GrDiffLine(GrDiffLineType.BOTH, 9, 11),
+            new GrDiffLine(GrDiffLineType.BOTH, 10, 12),
+            new GrDiffLine(GrDiffLineType.BOTH, 11, 13),
+          ],
+        }),
+        new GrDiffGroup({
+          type: GrDiffGroupType.BOTH,
+          lines: [
+            new GrDiffLine(GrDiffLineType.BOTH, 12, 14),
+            new GrDiffLine(GrDiffLineType.BOTH, 13, 15),
+            new GrDiffLine(GrDiffLineType.BOTH, 14, 16),
+          ],
+        }),
+      ];
+
+      groupsWithWhiteSpaceOnlyChange = [
+        groups[0],
+        new GrDiffGroup({
+          type: GrDiffGroupType.DELTA,
+          lines: [
+            new GrDiffLine(GrDiffLineType.REMOVE, 8),
+            new GrDiffLine(GrDiffLineType.ADD, 0, 10),
+            new GrDiffLine(GrDiffLineType.REMOVE, 9),
+            new GrDiffLine(GrDiffLineType.ADD, 0, 11),
+            new GrDiffLine(GrDiffLineType.REMOVE, 10),
+            new GrDiffLine(GrDiffLineType.ADD, 0, 12),
+            new GrDiffLine(GrDiffLineType.REMOVE, 11),
+            new GrDiffLine(GrDiffLineType.ADD, 0, 13),
+          ],
+          ignoredWhitespaceOnly: true,
+        }),
+        groups[2],
+      ];
+
+      groupsWithDelta = [
+        groups[0],
+        new GrDiffGroup({
           type: GrDiffGroupType.DELTA,
           lines: [
             new GrDiffLine(GrDiffLineType.REMOVE, 8),
@@ -120,14 +162,7 @@
             new GrDiffLine(GrDiffLineType.ADD, 0, 13),
           ],
         }),
-        new GrDiffGroup({
-          type: GrDiffGroupType.BOTH,
-          lines: [
-            new GrDiffLine(GrDiffLineType.BOTH, 12, 14),
-            new GrDiffLine(GrDiffLineType.BOTH, 13, 15),
-            new GrDiffLine(GrDiffLineType.BOTH, 14, 16),
-          ],
-        }),
+        groups[2],
       ];
     });
 
@@ -144,29 +179,33 @@
       assert.equal(collapsedGroups[2], groups[2]);
     });
 
+    test('does not hides when split is at delta group in context control', () => {
+      const collapsedGroups = hideInContextControl(groupsWithDelta, 3, 7);
+      assert.equal(collapsedGroups.length, 3);
+
+      assert.equal(collapsedGroups[0], groupsWithDelta[0]);
+      assert.equal(collapsedGroups[1], groupsWithDelta[1]);
+      assert.equal(collapsedGroups[2], groupsWithDelta[2]);
+    });
+
     test('splits partially hidden groups', () => {
       const collapsedGroups = hideInContextControl(groups, 4, 8);
       assert.equal(collapsedGroups.length, 4);
       assert.equal(collapsedGroups[0], groups[0]);
 
-      assert.equal(collapsedGroups[1].type, GrDiffGroupType.DELTA);
-      assert.deepEqual(collapsedGroups[1].adds, [groups[1].adds[0]]);
-      assert.deepEqual(collapsedGroups[1].removes, [groups[1].removes[0]]);
+      assert.equal(collapsedGroups[1].type, GrDiffGroupType.BOTH);
+      assert.deepEqual(collapsedGroups[1].lines, [groups[1].lines[0]]);
 
       assert.equal(collapsedGroups[2].type, GrDiffGroupType.CONTEXT_CONTROL);
       assert.equal(collapsedGroups[2].contextGroups.length, 2);
 
       assert.equal(
         collapsedGroups[2].contextGroups[0].type,
-        GrDiffGroupType.DELTA
+        GrDiffGroupType.BOTH
       );
       assert.deepEqual(
-        collapsedGroups[2].contextGroups[0].adds,
-        groups[1].adds.slice(1)
-      );
-      assert.deepEqual(
-        collapsedGroups[2].contextGroups[0].removes,
-        groups[1].removes.slice(1)
+        collapsedGroups[2].contextGroups[0].lines,
+        groups[1].lines.slice(1)
       );
 
       assert.equal(
@@ -181,6 +220,54 @@
       assert.deepEqual(collapsedGroups[3].lines, groups[2].lines.slice(1));
     });
 
+    test('splits partially hidden common delta groups', () => {
+      const collapsedGroups = hideInContextControl(
+        groupsWithWhiteSpaceOnlyChange,
+        4,
+        8
+      );
+      assert.equal(collapsedGroups.length, 4);
+      assert.equal(collapsedGroups[0], groupsWithWhiteSpaceOnlyChange[0]);
+
+      assert.equal(collapsedGroups[1].type, GrDiffGroupType.DELTA);
+      assert.deepEqual(collapsedGroups[1].adds, [
+        groupsWithWhiteSpaceOnlyChange[1].adds[0],
+      ]);
+      assert.deepEqual(collapsedGroups[1].removes, [
+        groupsWithWhiteSpaceOnlyChange[1].removes[0],
+      ]);
+
+      assert.equal(collapsedGroups[2].type, GrDiffGroupType.CONTEXT_CONTROL);
+      assert.equal(collapsedGroups[2].contextGroups.length, 2);
+
+      assert.equal(
+        collapsedGroups[2].contextGroups[0].type,
+        GrDiffGroupType.DELTA
+      );
+      assert.deepEqual(
+        collapsedGroups[2].contextGroups[0].adds,
+        groupsWithWhiteSpaceOnlyChange[1].adds.slice(1)
+      );
+      assert.deepEqual(
+        collapsedGroups[2].contextGroups[0].removes,
+        groupsWithWhiteSpaceOnlyChange[1].removes.slice(1)
+      );
+
+      assert.equal(
+        collapsedGroups[2].contextGroups[1].type,
+        GrDiffGroupType.BOTH
+      );
+      assert.deepEqual(collapsedGroups[2].contextGroups[1].lines, [
+        groupsWithWhiteSpaceOnlyChange[2].lines[0],
+      ]);
+
+      assert.equal(collapsedGroups[3].type, GrDiffGroupType.BOTH);
+      assert.deepEqual(
+        collapsedGroups[3].lines,
+        groupsWithWhiteSpaceOnlyChange[2].lines.slice(1)
+      );
+    });
+
     suite('with skip chunks', () => {
       setup(() => {
         const skipGroup = new GrDiffGroup({
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
index 90b9cfe..f3534c2 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
@@ -44,6 +44,7 @@
   RenderPreferences,
   GrDiff as GrDiffApi,
   DisplayLine,
+  DiffRangesToFocus,
   LineNumber,
   ContentLoadNeededEventDetail,
   DiffContextExpandedExternalDetail,
@@ -182,6 +183,9 @@
   @property({type: Object})
   lineOfInterest?: DisplayLine;
 
+  @property({type: Object})
+  diffRangesToFocus?: DiffRangesToFocus;
+
   /**
    * True when diff is changed, until the content is done rendering.
    * Use getter/setter loading instead of this.
@@ -368,7 +372,8 @@
       changedProperties.has('showNewlineWarningLeft') ||
       changedProperties.has('showNewlineWarningRight') ||
       changedProperties.has('prefs') ||
-      changedProperties.has('lineOfInterest')
+      changedProperties.has('lineOfInterest') ||
+      changedProperties.has('diffRangesToFocus')
     ) {
       if (this.diff && this.prefs) {
         const renderPrefs = {...(this.renderPrefs ?? {})};
@@ -394,6 +399,7 @@
           renderPrefs,
           diffPrefs: this.prefs,
           lineOfInterest: this.lineOfInterest,
+          diffRangesToFocus: this.diffRangesToFocus,
         });
       }
     }
diff --git a/polygerrit-ui/app/test/test-data-generators.ts b/polygerrit-ui/app/test/test-data-generators.ts
index 22dbe7c1..2309977 100644
--- a/polygerrit-ui/app/test/test-data-generators.ts
+++ b/polygerrit-ui/app/test/test-data-generators.ts
@@ -688,6 +688,27 @@
   });
 }
 
+export function createContextGroupWithDelta() {
+  return new GrDiffGroup({
+    type: GrDiffGroupType.CONTEXT_CONTROL,
+    contextGroups: [
+      new GrDiffGroup({
+        type: GrDiffGroupType.DELTA,
+        lines: [
+          new GrDiffLine(GrDiffLineType.REMOVE, 8),
+          new GrDiffLine(GrDiffLineType.ADD, 0, 10),
+          new GrDiffLine(GrDiffLineType.REMOVE, 9),
+          new GrDiffLine(GrDiffLineType.ADD, 0, 11),
+          new GrDiffLine(GrDiffLineType.REMOVE, 10),
+          new GrDiffLine(GrDiffLineType.ADD, 0, 12),
+          new GrDiffLine(GrDiffLineType.REMOVE, 11),
+          new GrDiffLine(GrDiffLineType.ADD, 0, 13),
+        ],
+      }),
+    ],
+  });
+}
+
 export function createBlame(): BlameInfo {
   return {
     author: 'test-author',
diff --git a/polygerrit-ui/app/types/diff.ts b/polygerrit-ui/app/types/diff.ts
index 2a8c7e5..0d1592e 100644
--- a/polygerrit-ui/app/types/diff.ts
+++ b/polygerrit-ui/app/types/diff.ts
@@ -16,6 +16,7 @@
   DiffFileMetaInfo as DiffFileMetaInfoApi,
   DiffInfo as DiffInfoApi,
   DiffIntralineInfo,
+  DiffRangesToFocus,
   DiffResponsiveMode,
   DiffPreferencesInfo as DiffPreferenceInfoApi,
   IgnoreWhitespaceType,
@@ -27,6 +28,7 @@
 export type {
   ChangeType,
   DiffIntralineInfo,
+  DiffRangesToFocus,
   DiffResponsiveMode,
   IgnoreWhitespaceType,
   MarkLength,