Merge "Allow user names that start with a numerical value" into stable-2.8
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties
index 333dcfa..b1001a4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/account/AccountConstants.properties
@@ -13,14 +13,14 @@
 maximumPageSizeFieldLabel = Maximum Page Size:
 commentVisibilityLabel = Comment Visibility:
 changeScreenLabel = Change View:
-diffViewLabel = Diff View (Change Screen 2):
+diffViewLabel = Diff View (New Change Screen):
 dateFormatLabel = Date/Time Format:
 contextWholeFile = Whole File
 buttonSaveChanges = Save Changes
 showRelativeDateInChangeTable = Show Relative Dates in Changes Table
 
 changeScreenOldUi = Old Screen
-changeScreenNewUi = Change Screen 2
+changeScreenNewUi = New Screen
 
 tabAccountSummary = Profile
 tabPreferences = Preferences
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.ui.xml
index bb2a04e..a4b19ff 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Actions.ui.xml
@@ -27,7 +27,7 @@
       margin: 6px 3px 0 0;
       border-color: rgba(0, 0, 0, 0.1);
       text-align: center;
-      font-size: 11px;
+      font-size: 8pt;
       font-weight: bold;
       border: 1px solid;
       cursor: pointer;
@@ -61,7 +61,6 @@
 
     #change_actions button.submit {
       float: right;
-      color: white;
       background-color: #4d90fe;
       background-image: -webkit-linear-gradient(top, #4d90fe, #4d90fe);
     }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml
index ce8a062..49883ee 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/ChangeScreen2.ui.xml
@@ -29,6 +29,10 @@
     @def INFO_WIDTH 450px;
     @def HEADER_HEIGHT 29px;
 
+    .cs2 {
+      margin-bottom: 1em;
+    }
+
     .headerLine {
       position: relative;
       background-color: trimColor;
@@ -213,7 +217,7 @@
       margin: 6px 3px 0 0;
       border-color: rgba(0, 0, 0, 0.1);
       text-align: center;
-      font-size: 11px;
+      font-size: 8pt;
       font-weight: bold;
       border: 1px solid;
       cursor: pointer;
@@ -231,7 +235,6 @@
       white-space: nowrap;
     }
     button.quickApprove {
-      color: #fff;
       background-color: #4d90fe;
       background-image: -webkit-linear-gradient(top, #4d90fe, #4d90fe);
     }
@@ -259,7 +262,7 @@
     }
   </ui:style>
 
-  <g:HTMLPanel>
+  <g:HTMLPanel styleName='{style.cs2}'>
     <g:HTMLPanel styleName='{style.headerLine}' ui:field='headerLine'>
       <div class='{style.idBlock}'>
         <c:StarIcon ui:field='star' styleName='{style.star}'/>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java
index 2d25409..6fcabee 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.java
@@ -41,6 +41,7 @@
   }
 
   @UiField Style style;
+  @UiField HTMLPanel header;
   @UiField Element name;
   @UiField Element summary;
   @UiField Element date;
@@ -58,7 +59,7 @@
     }
 
     initWidget(uiBinder.createAndBindUi(this));
-    addDomHandler(new ClickHandler() {
+    header.addDomHandler(new ClickHandler() {
       @Override
       public void onClick(ClickEvent event) {
         setOpen(!isOpen());
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.ui.xml
index e506340..b36fbb2 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/Message.ui.xml
@@ -85,9 +85,11 @@
       addStyleNames='{style.closed}'>
     <c:AvatarImage ui:field='avatar' styleName='{style.avatar}'/>
     <div class='{style.contents}'>
-      <div class='{style.name}' ui:field='name'/>
-      <div ui:field='summary' class='{style.summary}'/>
-      <div class='{style.date}' ui:field='date'/>
+      <g:HTMLPanel ui:field='header'>
+        <div class='{style.name}' ui:field='name'/>
+        <div ui:field='summary' class='{style.summary}'/>
+        <div class='{style.date}' ui:field='date'/>
+      </g:HTMLPanel>
       <div ui:field='message'
            aria-hidden='true'
            style='display: NONE'/>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RevisionsBox.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RevisionsBox.ui.xml
index 4c2f150..d7a8fc4 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RevisionsBox.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/change/RevisionsBox.ui.xml
@@ -46,6 +46,10 @@
     .table tr.current {
       background-color: selectionColor;
     }
+    .table tr.current a {
+      pointer-events: none;
+      color: #000;
+    }
 
     .legacy_id {
       min-width: 50px;
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBox.java
index 87073af..63b8cca 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/CommentBox.java
@@ -17,8 +17,6 @@
 import com.google.gerrit.client.changes.CommentInfo;
 import com.google.gerrit.client.diff.PaddingManager.PaddingWidgetWrapper;
 import com.google.gerrit.client.diff.SidePanel.GutterWrapper;
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.core.client.Scheduler.ScheduledCommand;
 import com.google.gwt.event.dom.client.MouseOutEvent;
 import com.google.gwt.event.dom.client.MouseOutHandler;
 import com.google.gwt.event.dom.client.MouseOverEvent;
@@ -82,9 +80,9 @@
     if (!getCommentInfo().has_line()) {
       return;
     }
-    Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+    parent.defer(new Runnable() {
       @Override
-      public void execute() {
+      public void run() {
         assert selfWidgetWrapper != null;
         selfWidgetWrapper.getWidget().changed();
         if (diffChunkInfo != null) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
index 2579cb8..9857484 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DiffTable.ui.xml
@@ -95,7 +95,8 @@
       cursor: pointer;
     }
     .difftable .CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
-      opacity: 0.8;
+      background: transparent;
+      text-decoration: underline;
       z-index: 2;
     }
     .showtabs .cm-tab:before {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.java
index d54df3a..d5cab44 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/DraftBox.java
@@ -25,7 +25,6 @@
 import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.RepeatingCommand;
-import com.google.gwt.core.client.Scheduler.ScheduledCommand;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
@@ -63,6 +62,7 @@
   private CommentInfo comment;
   private PublishedBox replyToBox;
   private Timer expandTimer;
+  private boolean autoClosed;
 
   @UiField Widget header;
   @UiField Element summary;
@@ -105,7 +105,12 @@
       @Override
       public void onClick(ClickEvent event) {
         if (!isEdit()) {
-          setOpen(!isOpen());
+          if (autoClosed && !isOpen()) {
+            setOpen(true);
+            setEdit(true);
+          } else {
+            setOpen(!isOpen());
+          }
         }
       }
     }, ClickEvent.getType());
@@ -129,6 +134,7 @@
   }
 
   private void set(CommentInfo info) {
+    autoClosed = info.message() != null && info.message().length() < 70;
     date.setInnerText(FormatUtil.shortFormatDayTime(info.updated()));
     if (info.message() != null) {
       String msg = info.message().trim();
@@ -229,12 +235,7 @@
     getCm().focus();
     getSelfWidgetWrapper().getWidget().clear();
     getGutterWrapper().remove();
-    Scheduler.get().scheduleDeferred(new ScheduledCommand() {
-      @Override
-      public void execute() {
-        resizePaddingWidget();
-      }
-    });
+    resizePaddingWidget();
   }
 
   @UiHandler("message")
@@ -275,11 +276,9 @@
       public void onSuccess(CommentInfo result) {
         enableEdit(true);
         set(result);
-        if (result.message().length() < 70) {
-          UIObject.setVisible(p_edit, false);
+        setEdit(false);
+        if (autoClosed) {
           setOpen(false);
-        } else {
-          setEdit(false);
         }
       }
 
@@ -311,6 +310,9 @@
       removeUI();
     } else {
       setEdit(false);
+      if (autoClosed) {
+        setOpen(false);
+      }
       getCm().focus();
     }
   }
@@ -349,6 +351,9 @@
         return;
       } else {
         setEdit(false);
+        if (autoClosed) {
+          setOpen(false);
+        }
         getCm().focus();
         return;
       }
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
index 9897f9a..4f7cd26 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/diff/SideBySide2.java
@@ -59,10 +59,11 @@
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiField;
-import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.rpc.AsyncCallback;
 import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.Widget;
 import com.google.gwtexpui.globalkey.client.GlobalKey;
 import com.google.gwtexpui.globalkey.client.KeyCommand;
 import com.google.gwtexpui.globalkey.client.KeyCommandSet;
@@ -133,6 +134,7 @@
   private KeyCommandSet keysComment;
   private KeyCommandSet keysOpenByEnter;
   private List<HandlerRegistration> handlers;
+  private List<Runnable> deferred;
 
   public SideBySide2(
       PatchSet.Id base,
@@ -231,11 +233,12 @@
   @Override
   public void onShowView() {
     super.onShowView();
-    resizeCodeMirror();
     Window.enableScrolling(false);
 
-    cmA.setOption("viewportMargin", 10);
-    cmB.setOption("viewportMargin", 10);
+    final int height = getCodeMirrorHeight();
+    cmA.setHeight(height);
+    cmB.setHeight(height);
+    diffTable.sidePanel.adjustGutters(cmB);
     cmB.setCursor(LineCharacter.create(0));
     cmB.focus();
 
@@ -412,57 +415,76 @@
     };
   }
 
-  private void display(DiffInfo diffInfo) {
-    cmA = displaySide(diffInfo.meta_a(), diffInfo.text_a(), diffTable.cmA);
-    cmB = displaySide(diffInfo.meta_b(), diffInfo.text_b(), diffTable.cmB);
-
+  private void display(final DiffInfo diffInfo) {
     skips = new ArrayList<SkippedLine>();
     linePaddingOnOtherSideMap = new HashMap<LineHandle, LinePaddingWidgetWrapper>();
     diffChunks = new ArrayList<DiffChunkInfo>();
-    render(diffInfo);
     lineActiveBoxMap = new HashMap<LineHandle, CommentBox>();
     linePublishedBoxesMap = new HashMap<LineHandle, List<PublishedBox>>();
     linePaddingManagerMap = new HashMap<LineHandle, PaddingManager>();
     if (publishedBase != null || publishedRevision != null) {
       publishedMap = new HashMap<String, PublishedBox>();
     }
-    if (publishedBase != null) {
-      renderPublished(publishedBase);
+
+    if (pref.isShowTabs()) {
+      diffTable.addStyleName(DiffTable.style.showtabs());
     }
-    if (publishedRevision != null) {
-      renderPublished(publishedRevision);
-    }
-    if (draftsBase != null) {
-      renderDrafts(draftsBase);
-    }
-    if (draftsRevision != null) {
-      renderDrafts(draftsRevision);
-    }
-    renderSkips();
+
+    cmA = createCodeMirror(diffInfo.meta_a(), diffInfo.text_a(), diffTable.cmA);
+    cmB = createCodeMirror(diffInfo.meta_b(), diffInfo.text_b(), diffTable.cmB);
+
+    cmA.operation(new Runnable() {
+      @Override
+      public void run() {
+        cmB.operation(new Runnable() {
+          @Override
+          public void run() {
+            // Estimate initial CM3 height, fixed up in onShowView.
+            int height = Window.getClientHeight()
+                - (Gerrit.getHeaderFooterHeight() + 18);
+            cmA.setHeight(height);
+            cmB.setHeight(height);
+
+            render(diffInfo);
+            if (publishedBase != null) {
+              renderPublished(publishedBase);
+            }
+            if (publishedRevision != null) {
+              renderPublished(publishedRevision);
+            }
+            if (draftsBase != null) {
+              renderDrafts(draftsBase);
+            }
+            if (draftsRevision != null) {
+              renderDrafts(draftsRevision);
+            }
+            renderSkips();
+          }
+        });
+      }
+    });
+
     registerCmEvents(cmA);
     registerCmEvents(cmB);
 
     scrollingGlue = GWT.create(ScrollSynchronizer.class);
     scrollingGlue.init(diffTable, cmA, cmB, mapper);
-
     resizeHandler = Window.addResizeHandler(new ResizeHandler() {
       @Override
       public void onResize(ResizeEvent event) {
         resizeCodeMirror();
       }
     });
-    if (pref.isShowTabs()) {
-      diffTable.addStyleName(DiffTable.style.showtabs());
-    }
   }
 
-  private CodeMirror displaySide(DiffInfo.FileMeta meta, String contents,
-      Element ele) {
-    if (meta == null) {
-      contents = "";
-    }
+  private CodeMirror createCodeMirror(
+      DiffInfo.FileMeta meta,
+      String contents,
+      Element parent) {
     Configuration cfg = Configuration.create()
       .set("readOnly", true)
+      .set("cursorBlinkRate", 0)
+      .set("cursorHeight", 0.85)
       .set("lineNumbers", true)
       .set("tabSize", pref.getTabSize())
       .set("mode", getContentType(meta))
@@ -470,17 +492,8 @@
       .set("styleSelectedText", true)
       .set("showTrailingSpace", pref.isShowWhitespaceErrors())
       .set("keyMap", "vim_ro")
-      .set("value", contents)
-      /**
-       * Without this, CM won't put line widgets too far down in the right spot,
-       * and padding widgets will be informed of wrong offset height. Reset to
-       * 10 (default) after initial rendering.
-       */
-      .setInfinity("viewportMargin");
-    int h = Gerrit.getHeaderFooterHeight() + 18 /* reviewed estimate */;
-    CodeMirror cm = CodeMirror.create(ele, cfg);
-    cm.setHeight(Window.getClientHeight() - h);
-    return cm;
+      .set("value", meta != null ? contents : "");
+    return CodeMirror.create(parent, cfg);
   }
 
   private void render(DiffInfo diff) {
@@ -587,12 +600,14 @@
       return box;
     }
     addCommentBox(info, box);
+    box.setVisible(true);
     LineHandle handle = cm.getLineHandle(info.line() - 1);
     lineActiveBoxMap.put(handle, box);
     return box;
   }
 
   CommentBox addCommentBox(CommentInfo info, CommentBox box) {
+    box.setParent(this);
     diffTable.add(box);
     DisplaySide side = box.getSide();
     CodeMirror cm = getCmFromSide(side);
@@ -628,16 +643,15 @@
       .set("coverGutter", true)
       .set("insertAt", index)
       .set("noHScroll", true);
-    LineWidget boxWidget = cm.addLineWidget(line, box.getElement(), config);
+    LineWidget boxWidget = addLineWidget(cm, line, box, config);
     box.setPaddingManager(manager);
     box.setSelfWidgetWrapper(new PaddingWidgetWrapper(boxWidget, box.getElement()));
-    box.setParent(this);
     if (otherChunk == null) {
       box.setDiffChunkInfo(myChunk);
     }
     box.setGutterWrapper(diffTable.sidePanel.addGutter(cm, info.line() - 1,
-        box instanceof DraftBox ?
-            SidePanel.GutterType.DRAFT
+        box instanceof DraftBox
+          ? SidePanel.GutterType.DRAFT
           : SidePanel.GutterType.COMMENT));
     return box;
   }
@@ -795,7 +809,7 @@
   private SkipBar renderSkipHelper(CodeMirror cm, SkippedLine skip) {
     int size = skip.getSize();
     int markStart = cm == cmA ? skip.getStartA() : skip.getStartB();
-    int markEnd = markStart + size;
+    int markEnd = markStart + size - 1;
     SkipBar bar = new SkipBar(cm);
     diffTable.add(bar);
     Configuration markerConfig = Configuration.create()
@@ -806,11 +820,11 @@
         .set("coverGutter", true)
         .set("noHScroll", true);
     if (markStart == 0) {
-      bar.setWidget(cm.addLineWidget(
-          markEnd + 1, bar.getElement(), lineWidgetConfig.set("above", true)));
+      bar.setWidget(addLineWidget(
+          cm, markEnd + 1, bar, lineWidgetConfig.set("above", true)));
     } else {
-      bar.setWidget(cm.addLineWidget(
-          markStart - 1, bar.getElement(), lineWidgetConfig));
+      bar.setWidget(addLineWidget(
+          cm, markStart - 1, bar, lineWidgetConfig));
     }
     bar.setMarker(cm.markText(CodeMirror.pos(markStart, 0),
         CodeMirror.pos(markEnd), markerConfig), size);
@@ -887,8 +901,8 @@
 
   private PaddingWidgetWrapper addPaddingWidget(CodeMirror cm,
       int line, double height, Unit unit, Integer index) {
-    Element div = DOM.createDiv();
-    div.getStyle().setHeight(height, unit);
+    SimplePanel padding = new SimplePanel();
+    padding.getElement().getStyle().setHeight(height, unit);
     Configuration config = Configuration.create()
         .set("coverGutter", true)
         .set("above", line == -1)
@@ -896,8 +910,28 @@
     if (index != null) {
       config = config.set("insertAt", index);
     }
-    LineWidget widget = cm.addLineWidget(line == -1 ? 0 : line, div, config);
-    return new PaddingWidgetWrapper(widget, div);
+    LineWidget widget = addLineWidget(cm, line == -1 ? 0 : line, padding, config);
+    return new PaddingWidgetWrapper(widget, padding.getElement());
+  }
+
+  /**
+   * A LineWidget needs to be added to diffTable in order to respond to browser
+   * events, but CodeMirror doesn't render the widget until the containing line
+   * is scrolled into viewportMargin, causing it to appear at the bottom of the
+   * DOM upon loading. Fix by hiding the widget until it is first scrolled into
+   * view (when CodeMirror fires a "redraw" event on the widget).
+   */
+  private LineWidget addLineWidget(CodeMirror cm, int line,
+      final Widget widget, Configuration options) {
+    widget.setVisible(false);
+    LineWidget lineWidget = cm.addLineWidget(line, widget.getElement(), options);
+    lineWidget.onFirstRedraw(new Runnable() {
+      @Override
+      public void run() {
+        widget.setVisible(true);
+      }
+    });
+    return lineWidget;
   }
 
   private void clearActiveLine(CodeMirror cm) {
@@ -934,9 +968,9 @@
          * key (or j/k) is held down. Performance on Chrome is fine
          * without the deferral.
          */
-        Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+        defer(new Runnable() {
           @Override
-          public void execute() {
+          public void run() {
             LineHandle handle = cm.getLineHandleVisualStart(
                 cm.getCursor("end").getLine());
             if (cm.hasActiveLine() && cm.getActiveLine().equals(handle)) {
@@ -1171,6 +1205,33 @@
     return (index + diffChunks.size()) % diffChunks.size();
   }
 
+  void defer(Runnable thunk) {
+    if (deferred == null) {
+      final ArrayList<Runnable> list = new ArrayList<Runnable>();
+      deferred = list;
+      Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+        @Override
+        public void execute() {
+          deferred = null;
+          cmA.operation(new Runnable() {
+            @Override
+            public void run() {
+              cmB.operation(new Runnable() {
+                @Override
+                public void run() {
+                  for (Runnable thunk : list) {
+                    thunk.run();
+                  }
+                }
+              });
+            }
+          });
+        }
+      });
+    }
+    deferred.add(thunk);
+  }
+
   void resizePaddingOnOtherSide(DisplaySide mySide, int line) {
     CodeMirror cm = getCmFromSide(mySide);
     LineHandle handle = cm.getLineHandle(line);
@@ -1226,9 +1287,9 @@
           lineActiveBoxMap.get(handle).resizePaddingWidget();
         }
         if (linePaddingOnOtherSideMap.containsKey(handle)) {
-          Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+          defer(new Runnable() {
             @Override
-            public void execute() {
+            public void run() {
               resizePaddingOnOtherSide(side, instance.getLineNumber(handle));
             }
           });
@@ -1238,16 +1299,18 @@
   }
 
   void resizeCodeMirror() {
+    int height = getCodeMirrorHeight();
+    cmA.setHeight(height);
+    cmB.setHeight(height);
+    diffTable.sidePanel.adjustGutters(cmB);
+  }
+
+  private int getCodeMirrorHeight() {
     int rest = Gerrit.getHeaderFooterHeight()
         + header.getOffsetHeight()
         + diffTable.getHeaderHeight()
-        + 10; // Estimate
-    int h = Window.getClientHeight() - rest;
-    cmA.setHeight(h);
-    cmB.setHeight(h);
-    cmA.refresh();
-    cmB.refresh();
-    diffTable.sidePanel.adjustGutters(cmB);
+        + 5; // Estimate
+    return Window.getClientHeight() - rest;
   }
 
   static void setHeightInPx(Element ele, double height) {
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
index c5a047c..4652f86 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/CodeMirror.java
@@ -48,10 +48,6 @@
     this.setOption(option, val);
   }-*/;
 
-  public final native void setOptionToInfinity(String option) /*-{
-    this.setOption(option, Infinity);
-  }-*/;
-
   public final native void setValue(String v) /*-{ this.setValue(v); }-*/;
 
   public final native void setWidth(double w) /*-{ this.setSize(w, null); }-*/;
@@ -166,6 +162,12 @@
     this.state.oldViewportSize = lines;
   }-*/;
 
+  public final native void operation(Runnable thunk) /*-{
+    this.operation(function() {
+      thunk.@java.lang.Runnable::run()();
+    });
+  }-*/;
+
   public final native void on(String event, Runnable thunk) /*-{
     this.on(event, $entry(function() {
       thunk.@java.lang.Runnable::run()();
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/Configuration.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/Configuration.java
index 862e0f7..7a0bbea 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/Configuration.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/Configuration.java
@@ -33,15 +33,15 @@
   public final native Configuration set(String name, int val)
   /*-{ this[name] = val; return this; }-*/;
 
+  public final native Configuration set(String name, double val)
+  /*-{ this[name] = val; return this; }-*/;
+
   public final native Configuration set(String name, boolean val)
   /*-{ this[name] = val; return this; }-*/;
 
   public final native Configuration set(String name, JavaScriptObject val)
   /*-{ this[name] = val; return this; }-*/;
 
-  public final native Configuration setInfinity(String name)
-  /*-{ this[name] = Infinity; return this; }-*/;
-
   protected Configuration() {
   }
 }
diff --git a/gerrit-gwtui/src/main/java/net/codemirror/lib/LineWidget.java b/gerrit-gwtui/src/main/java/net/codemirror/lib/LineWidget.java
index c7b0300..bd1e0a3 100644
--- a/gerrit-gwtui/src/main/java/net/codemirror/lib/LineWidget.java
+++ b/gerrit-gwtui/src/main/java/net/codemirror/lib/LineWidget.java
@@ -24,6 +24,16 @@
 
   public final native void clear() /*-{ this.clear(); }-*/;
   public final native void changed() /*-{ this.changed(); }-*/;
+
+  public final native void onFirstRedraw(Runnable thunk) /*-{
+    var w = this;
+    var h = $entry(function() {
+      thunk.@java.lang.Runnable::run()();
+      w.off("redraw", h);
+    });
+    w.on("redraw", h);
+  }-*/;
+
   public final native JavaScriptObject getLine() /*-{ return this.line; }-*/;
 
   protected LineWidget() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
index c111c02..ddfe752 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java
@@ -490,6 +490,10 @@
   }
 
   public boolean canReadCommit(RevWalk rw, RevCommit commit) {
+    if (controlForRef("refs/*").canPerform(Permission.READ)) {
+      return true;
+    }
+
     Project.NameKey projName = state.getProject().getNameKey();
     try {
       Repository repo = repoManager.openRepository(projName);
@@ -521,6 +525,6 @@
               commit.name(), projName.get());
       log.error(msg, e);
     }
-    return controlForRef("refs/*").canPerform(Permission.READ);
+    return false;
   }
 }