Reland of grit: Automatically replace ... with …

Previous change: https://codereview.chromium.org/2176663003/

Reason for Reland:
I've added rebaselines to TestExpectations, following:
https://www.chromium.org/developers/testing/webkit-layout-tests/testexpectations#TOC-How-to-rebaseline

TBR=flackr@chromium.org,asanka@chromium.org,mpearson@chromium.org
BUG=621772

Review-Url: https://codereview.chromium.org/2177963002
Cr-Commit-Position: refs/heads/master@{#407548}
diff --git a/chrome/browser/download/download_item_model_unittest.cc b/chrome/browser/download/download_item_model_unittest.cc
index be3049d..dfb07fe 100644
--- a/chrome/browser/download/download_item_model_unittest.cc
+++ b/chrome/browser/download/download_item_model_unittest.cc
@@ -308,9 +308,9 @@
     //         .-- .TimeRemaining() is known.
     //        |       .-- .GetOpenWhenComplete()
     //        |      |      .---- .IsPaused()
-    { 0, 0, false, false, false, "Starting..." },
+    { 0, 0, false, false, false, "Starting\xE2\x80\xA6" },
     { 1, 0, false, false, false, "1 B" },
-    { 0, 2, false, false, false, "Starting..." },
+    { 0, 2, false, false, false, "Starting\xE2\x80\xA6"},
     { 1, 2, false, false, false, "1/2 B" },
     { 0, 2, true,  false, false, "0/2 B, 10 secs left" },
     { 1, 2, true,  false, false, "1/2 B, 10 secs left" },
@@ -318,8 +318,8 @@
     { 1, 0, false, true,  false, "Opening when complete" },
     { 0, 2, false, true,  false, "Opening when complete" },
     { 1, 2, false, true,  false, "Opening when complete" },
-    { 0, 2, true,  true,  false, "Opening in 10 secs..." },
-    { 1, 2, true,  true,  false, "Opening in 10 secs..." },
+    { 0, 2, true,  true,  false, "Opening in 10 secs\xE2\x80\xA6"},
+    { 1, 2, true,  true,  false, "Opening in 10 secs\xE2\x80\xA6"},
     { 0, 0, false, false, true,  "0 B, Paused" },
     { 1, 0, false, false, true,  "1 B, Paused" },
     { 0, 2, false, false, true,  "0/2 B, Paused" },
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 084cc94..b5cbba59 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -479,6 +479,12 @@
 # Ref tests that needs investigation.
 crbug.com/404597 [ Mac ] fast/css3-text/css3-text-justify/text-justify-crash.html [ Failure ]
 crbug.com/404597 fast/forms/long-text-in-input.html [ Failure ]
+crbug.com/621772 fast/forms/color/color-suggestion-picker-appearance.html [ NeedsRebaseline ]
+crbug.com/621772 fast/forms/color/color-suggestion-picker-appearance-zoom125.html [ NeedsRebaseline ]
+crbug.com/621772 fast/forms/color/color-suggestion-picker-appearance-zoom200.html [ NeedsRebaseline ]
+crbug.com/621772 fast/forms/color/color-suggestion-picker-one-row-appearance.html [ NeedsRebaseline ]
+crbug.com/621772 fast/forms/color/color-suggestion-picker-two-row-appearance.html [ NeedsRebaseline ]
+crbug.com/621772 fast/forms/color/color-suggestion-picker-with-scrollbar-appearance.html [ NeedsRebaseline ]
 
 # Ref test needs updating due to new font metrics.
 crbug.com/404597 fast/css/text-overflow-ellipsis-button.html [ Pass Failure ]
diff --git a/tools/grit/grit/node/message.py b/tools/grit/grit/node/message.py
index 48cd1c79..e3024fb 100755
--- a/tools/grit/grit/node/message.py
+++ b/tools/grit/grit/node/message.py
@@ -11,15 +11,16 @@
 
 from grit.node import base
 
-import grit.format.rc_header
-import grit.format.rc
-
 from grit import clique
 from grit import exception
 from grit import lazy_re
 from grit import tclib
 from grit import util
 
+
+# Matches exactly three dots ending a line or followed by whitespace.
+_ELLIPSIS_PATTERN = lazy_re.compile(r'(?<!\.)\.\.\.(?=$|\s)')
+_ELLIPSIS_SYMBOL = u'\u2026'  # Ellipsis
 # Finds whitespace at the start and end of a string which can be multiline.
 _WHITESPACE = lazy_re.compile('(?P<start>\s*)(?P<body>.+?)(?P<end>\s*)\Z',
                               re.DOTALL | re.MULTILINE)
@@ -54,6 +55,9 @@
     # Example: "foo=5 bar baz=100"
     self.formatter_data = {}
 
+    # Whether or not to convert ... -> U+2026 within Translate().
+    self._replace_ellipsis = False
+
   def _IsValidChild(self, child):
     return isinstance(child, (PhNode))
 
@@ -68,6 +72,11 @@
       return False
     return True
 
+  def SetReplaceEllipsis(self, value):
+    '''Sets whether to replace ... with \u2026.
+    '''
+    self._replace_ellipsis = value
+
   def MandatoryAttributes(self):
     return ['name|offset']
 
@@ -200,6 +209,8 @@
                                          self.PseudoIsAllowed(),
                                          self.ShouldFallbackToEnglish()
                                          ).GetRealContent()
+    if self._replace_ellipsis:
+      msg = _ELLIPSIS_PATTERN.sub(_ELLIPSIS_SYMBOL, msg)
     return msg.replace('[GRITLANGCODE]', lang)
 
   def NameOrOffset(self):
diff --git a/tools/grit/grit/node/message_unittest.py b/tools/grit/grit/node/message_unittest.py
index a058257a..3592af37 100755
--- a/tools/grit/grit/node/message_unittest.py
+++ b/tools/grit/grit/node/message_unittest.py
@@ -8,12 +8,16 @@
 
 import os
 import sys
-if __name__ == '__main__':
-  sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
-
 import unittest
 import StringIO
 
+if __name__ == '__main__':
+  # When executed as the main module, the first entry in sys.path will be
+  # the directory contain this module. This entry causes the io.py file in this
+  # directory to be selected whenever any file does "import io", rather than the
+  # system "io" module. As a work-around, remove the first sys.path entry.
+  sys.path[0] = os.path.join(os.path.dirname(__file__), '../..')
+
 from grit import tclib
 from grit import util
 from grit.node import message
@@ -85,6 +89,18 @@
       self.failUnlessEqual(expected_formatter_data[key],
                            msg.formatter_data[key])
 
+  def testReplaceEllipsis(self):
+    root = util.ParseGrdForUnittest('''
+        <messages>
+        <message name="IDS_GREETING" desc="">
+        A...B.... <ph name="PH">%s<ex>A</ex></ph>... B... C...
+        </message>
+        </messages>''')
+    msg, = root.GetChildrenOfType(message.MessageNode)
+    msg.SetReplaceEllipsis(True)
+    content = msg.Translate('en')
+    self.failUnlessEqual(u'A...B.... %s\u2026 B\u2026 C\u2026', content)
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py
index 65a966f..51d3341 100755
--- a/tools/grit/grit/tool/build.py
+++ b/tools/grit/grit/tool/build.py
@@ -15,9 +15,12 @@
 import sys
 
 from grit import grd_reader
-from grit import util
-from grit.tool import interface
 from grit import shortcuts
+from grit import util
+from grit.node import include
+from grit.node import message
+from grit.node import structure
+from grit.tool import interface
 
 
 # It would be cleaner to have each module register itself, but that would
@@ -145,10 +148,12 @@
     output_all_resource_defines = None
     write_only_new = False
     depend_on_stamp = False
+    replace_ellipsis = True
     (own_opts, args) = getopt.getopt(args, 'a:o:D:E:f:w:t:h:',
         ('depdir=','depfile=','assert-file-list=',
          'output-all-resource-defines',
          'no-output-all-resource-defines',
+         'no-replace-ellipsis',
          'depend-on-stamp',
          'write-only-new='))
     for (key, val) in own_opts:
@@ -176,6 +181,8 @@
         output_all_resource_defines = True
       elif key == '--no-output-all-resource-defines':
         output_all_resource_defines = False
+      elif key == '--no-replace-ellipsis':
+        replace_ellipsis = False
       elif key == '-t':
         target_platform = val
       elif key == '-h':
@@ -227,6 +234,13 @@
     if rc_header_format:
       self.res.AssignRcHeaderFormat(rc_header_format)
     self.res.RunGatherers()
+
+    # Replace ... with the single-character version. http://crbug.com/621772
+    if replace_ellipsis:
+      for node in self.res:
+        if isinstance(node, message.MessageNode):
+          node.SetReplaceEllipsis(True)
+
     self.Process()
 
     if assert_output_files:
@@ -267,9 +281,6 @@
   def AddWhitelistTags(start_node, whitelist_names):
     # Walk the tree of nodes added attributes for the nodes that shouldn't
     # be written into the target files (skip markers).
-    from grit.node import include
-    from grit.node import message
-    from grit.node import structure
     for node in start_node:
       # Same trick data_pack.py uses to see what nodes actually result in
       # real items.