SideBySide2: Correct placement of column margin bar

Some browsers (Chrome, Firefox) are now using non-integer font widths
for the fixed width text display from CM3. Chrome on Mac OS X is now
measuring 7.2 pixels per character.

Unfortunately this can only be discovered by measuring the width of an
element with more than 1 character in it.  CM3's defaultCharWidth()
function measures the width of a single "x" and assumes this is going
to be accurate.  Except the browser rounds down and returns 7.0, which
is 0.2 short for longer runs of text.

Measure a 100 character string in a span and take the average width of
these 100 characters to identify the real character width used for
text in a CM3 instance.  This is now coming in around 7.2 px, which
can be multipled out with the integral columns to get the margin bar
positioned at the desired location in source files.

The string length needs to be long enough that most browsers will show
evidence of fractional character widths.  100 is a good guess as some
coding standard conventions limit lines to 100 (or even 80),
suggesting no conforming code would even reach this length of 100.

If the margin was set at 100, and the measurement was taken for 100
but is still flawed, at worst the margin bar should position correctly
at 100.  It also gives about 2 decimal places of precision on the char
width, assuming fractional widths are being used by the browser.  This
may be fine for 100 character wide line lengths, any residual error
should be small enough to go unnoticed.

Issue: 2918
Change-Id: I37f328f1c5475f4aaa2ad1c90b6339fdc2c6ef5c
This commit is contained in:
Shawn Pearce 2014-11-06 16:59:47 -08:00 committed by David Pursehouse
parent 80ad102bdb
commit e07fc849e4

View File

@ -43,7 +43,7 @@ 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.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
@ -101,6 +101,7 @@ public class SideBySide2 extends Screen {
private CodeMirror cmB;
private Element columnMarginA;
private Element columnMarginB;
private double charWidthPx;
private HandlerRegistration resizeHandler;
private DiffInfo diff;
private boolean largeFile;
@ -580,13 +581,32 @@ public class SideBySide2 extends Screen {
}
void setLineLength(int columns) {
columnMarginA.getStyle().setMarginLeft(
columns * cmA.defaultCharWidth()
+ cmA.getGutterElement().getOffsetWidth(), Unit.PX);
double w = columns * getCharWidthPx();
columnMarginA.getStyle().setMarginLeft(w, Style.Unit.PX);
columnMarginB.getStyle().setMarginLeft(w, Style.Unit.PX);
}
columnMarginB.getStyle().setMarginLeft(
columns * cmB.defaultCharWidth()
+ cmB.getGutterElement().getOffsetWidth(), Unit.PX);
private double getCharWidthPx() {
if (charWidthPx <= 1) {
int len = 100;
StringBuilder s = new StringBuilder();
for (int i = 0; i < len; i++) {
s.append('m');
}
Element e = DOM.createSpan();
e.getStyle().setDisplay(Style.Display.INLINE_BLOCK);
e.setInnerText(s.toString());
cmA.getMoverElement().appendChild(e);
double a = ((double) e.getOffsetWidth()) / len;
e.removeFromParent();
cmB.getMoverElement().appendChild(e);
double b = ((double) e.getOffsetWidth()) / len;
e.removeFromParent();
charWidthPx = Math.max(a, b);
}
return charWidthPx;
}
void setShowLineNumbers(boolean b) {