Add the ability for keys to be drawn as an image.

Some keys are now drawn as images instead of as text.

R=viettrungluu@chromium.org

Review URL: https://codereview.chromium.org/1149293002
diff --git a/.gitignore b/.gitignore
index 27f8e12..7d985b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,3 +77,6 @@
 # sky tools
 /sky/tools/skygo/linux64/sky_server
 /sky/tools/skygo/mac/sky_server
+
+# downloaded keyboard_native resources.
+/services/keyboard_native/res/*.png
diff --git a/DEPS b/DEPS
index 3e481a7..a367029 100644
--- a/DEPS
+++ b/DEPS
@@ -366,4 +366,15 @@
                 '-s', 'src/third_party/dejavu-fonts-ttf-2.34/ttf/DejaVuSansMono.ttf.sha1',
     ],
   },
+  # Pull keyboard_native resources using checked-in hashes.
+  {
+    'name': 'keyboard_native_resources',
+    'pattern': '',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--no_auth',
+                '--bucket', 'mojo/keyboard_native',
+                '-d', 'src/services/keyboard_native/res',
+    ],
+  },
 ]
diff --git a/services/keyboard_native/BUILD.gn b/services/keyboard_native/BUILD.gn
index e3064ea..a52b517 100644
--- a/services/keyboard_native/BUILD.gn
+++ b/services/keyboard_native/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//mojo/public/mojo_application.gni")
+import("//mojo/tools/embed/rules.gni")
 
 mojo_native_application("keyboard_native") {
   sources = [
@@ -26,6 +27,10 @@
   ]
 
   deps = [
+    ":action_icon",
+    ":delete_icon",
+    ":lower_case_icon",
+    ":upper_case_icon",
     "//base",
     "//mojo/application",
     "//mojo/public/cpp/bindings",
@@ -43,6 +48,31 @@
     "//mojo/services/view_manager/public/cpp",
     "//mojo/skia",
     "//skia",
+    "//ui/gfx",
     "//ui/gfx/geometry",
   ]
 }
+
+embed_file("action_icon") {
+  source = "res/Emoticon.png"
+  namespace = "keyboard_native"
+  variable = "kActionIcon"
+}
+
+embed_file("delete_icon") {
+  source = "res/Delete.png"
+  namespace = "keyboard_native"
+  variable = "kDeleteIcon"
+}
+
+embed_file("lower_case_icon") {
+  source = "res/ArrowDown.png"
+  namespace = "keyboard_native"
+  variable = "kLowerCaseIcon"
+}
+
+embed_file("upper_case_icon") {
+  source = "res/ArrowUp.png"
+  namespace = "keyboard_native"
+  variable = "kUpperCaseIcon"
+}
diff --git a/services/keyboard_native/key_layout.cc b/services/keyboard_native/key_layout.cc
index 13957cb..53b849d 100644
--- a/services/keyboard_native/key_layout.cc
+++ b/services/keyboard_native/key_layout.cc
@@ -5,36 +5,100 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/macros.h"
+#include "mojo/tools/embed/data.h"
+#include "services/keyboard_native/kActionIcon.h"
+#include "services/keyboard_native/kDeleteIcon.h"
+#include "services/keyboard_native/kLowerCaseIcon.h"
+#include "services/keyboard_native/kUpperCaseIcon.h"
 #include "services/keyboard_native/key_layout.h"
 #include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkImageDecoder.h"
+#include "third_party/skia/include/core/SkStream.h"
 #include "third_party/skia/include/core/SkTypeface.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
 
 namespace keyboard {
 
-KeyLayout::TextKey::TextKey(
-    const char* text,
-    base::Callback<void(const TextKey&)> touch_up_callback)
-    : text_(text), touch_up_callback_(touch_up_callback) {
-}
+// An implementation of Key that draws itself as ASCII text.
+class KeyLayout::TextKey : public Key {
+ public:
+  TextKey(const char* text,
+          base::Callback<void(const TextKey&)> touch_up_callback)
+      : text_(text), touch_up_callback_(touch_up_callback) {}
 
-KeyLayout::TextKey::~TextKey() {
-}
+  ~TextKey() override {}
 
-void KeyLayout::TextKey::Draw(SkCanvas* canvas,
-                              SkPaint paint,
-                              const gfx::RectF& rect) {
-  float text_baseline_offset = rect.height() / 5.0f;
-  canvas->drawText(text_, strlen(text_), rect.x() + (rect.width() / 2.0f),
-                   rect.y() + rect.height() - text_baseline_offset, paint);
-}
+  void Draw(SkCanvas* canvas,
+            const SkPaint& paint,
+            const gfx::RectF& rect) override {
+    float text_baseline_offset = rect.height() / 5.0f;
+    canvas->drawText(text_, strlen(text_), rect.x() + (rect.width() / 2.0f),
+                     rect.y() + rect.height() - text_baseline_offset, paint);
+  }
 
-const char* KeyLayout::TextKey::ToText() const {
-  return text_;
-}
+  const char* ToText() const override { return text_; }
 
-void KeyLayout::TextKey::OnTouchUp() {
-  touch_up_callback_.Run(*this);
-}
+  void OnTouchUp() override { touch_up_callback_.Run(*this); }
+
+ private:
+  const char* text_;
+  base::Callback<void(const TextKey&)> touch_up_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(TextKey);
+};
+
+// An implementation of Key that draws itself as an image.
+class ImageKey : public KeyLayout::Key {
+ public:
+  ImageKey(const char* text,
+           base::Callback<void(const KeyLayout::TextKey&)> touch_up_callback,
+           const mojo::embed::Data& data)
+      : text_key_(text, touch_up_callback), bitmap_valid_(false), bitmap_() {
+    bool result = gfx::PNGCodec::Decode(
+        reinterpret_cast<const unsigned char*>(data.data), data.size, &bitmap_);
+    bitmap_valid_ = result && bitmap_.width() > 0 && bitmap_.height() > 0;
+    DCHECK(bitmap_valid_);
+  }
+  ~ImageKey() override {}
+
+  // Key implementation.
+  void Draw(SkCanvas* canvas,
+            const SkPaint& paint,
+            const gfx::RectF& rect) override {
+    // If our bitmap is somehow invalid, default to drawing the text of the key.
+    if (!bitmap_valid_) {
+      text_key_.Draw(canvas, paint, rect);
+      return;
+    }
+
+    float width_scale = rect.width() / bitmap_.width();
+    float height_scale = rect.height() / bitmap_.height();
+    float scale = width_scale > height_scale ? height_scale : width_scale;
+    float target_width = bitmap_.width() * scale;
+    float target_height = bitmap_.height() * scale;
+    float delta_width = rect.width() - target_width;
+    float target_x = rect.x() + (delta_width / 2.0f);
+    float delta_height = rect.height() - target_height;
+    float target_y = rect.y() + (delta_height / 2.0f);
+    canvas->drawBitmapRect(
+        bitmap_,
+        SkRect::MakeXYWH(target_x, target_y, target_width, target_height),
+        &paint);
+  }
+  const char* ToText() const override { return text_key_.ToText(); }
+  void OnTouchUp() override { text_key_.OnTouchUp(); }
+
+ private:
+  KeyLayout::TextKey text_key_;
+  bool bitmap_valid_;
+  SkBitmap bitmap_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImageKey);
+};
 
 KeyLayout::KeyLayout()
     : on_text_callback_(),
@@ -199,6 +263,15 @@
   base::Callback<void(const TextKey&)> switch_to_symbols_callback =
       base::Bind(&KeyLayout::OnKeySwitchToSymbols, weak_factory_.GetWeakPtr());
 
+  ImageKey* switch_to_upper_case_image_key = new ImageKey(
+      "/\\", switch_to_upper_case_callback, keyboard_native::kUpperCaseIcon);
+  ImageKey* switch_to_lower_case_image_key = new ImageKey(
+      "\\/", switch_to_lower_case_callback, keyboard_native::kLowerCaseIcon);
+  ImageKey* delete_image_key =
+      new ImageKey("<-", delete_callback, keyboard_native::kDeleteIcon);
+  ImageKey* action_image_key =
+      new ImageKey(":)", do_nothing_callback, keyboard_native::kActionIcon);
+
   std::vector<Key*> lower_case_key_map_row_one = {
       new TextKey("q", emit_text_callback),
       new TextKey("w", emit_text_callback),
@@ -223,7 +296,7 @@
       new TextKey("l", emit_text_callback)};
 
   std::vector<Key*> lower_case_key_map_row_three = {
-      new TextKey("/\\", switch_to_upper_case_callback),
+      switch_to_upper_case_image_key,
       new TextKey("z", emit_text_callback),
       new TextKey("x", emit_text_callback),
       new TextKey("c", emit_text_callback),
@@ -231,14 +304,14 @@
       new TextKey("b", emit_text_callback),
       new TextKey("n", emit_text_callback),
       new TextKey("m", emit_text_callback),
-      new TextKey("del", delete_callback)};
+      delete_image_key};
 
   std::vector<Key*> lower_case_key_map_row_four = {
       new TextKey("sym", switch_to_symbols_callback),
       new TextKey(",", emit_text_callback),
       new TextKey(" ", emit_text_callback),
       new TextKey(".", emit_text_callback),
-      new TextKey("act", do_nothing_callback)};
+      action_image_key};
 
   lower_case_key_map_ = {lower_case_key_map_row_one,
                          lower_case_key_map_row_two,
@@ -269,7 +342,7 @@
       new TextKey("L", emit_text_callback)};
 
   std::vector<Key*> upper_case_key_map_row_three = {
-      new TextKey("\\/", switch_to_lower_case_callback),
+      switch_to_lower_case_image_key,
       new TextKey("Z", emit_text_callback),
       new TextKey("X", emit_text_callback),
       new TextKey("C", emit_text_callback),
@@ -277,14 +350,14 @@
       new TextKey("B", emit_text_callback),
       new TextKey("N", emit_text_callback),
       new TextKey("M", emit_text_callback),
-      new TextKey("DEL", delete_callback)};
+      delete_image_key};
 
   std::vector<Key*> upper_case_key_map_row_four = {
       new TextKey("SYM", switch_to_symbols_callback),
       new TextKey(",", emit_text_callback),
       new TextKey(" ", emit_text_callback),
       new TextKey(".", emit_text_callback),
-      new TextKey("ACT", do_nothing_callback)};
+      action_image_key};
 
   upper_case_key_map_ = {upper_case_key_map_row_one,
                          upper_case_key_map_row_two,
@@ -323,7 +396,7 @@
       new TextKey(";", emit_text_callback),
       new TextKey("!", emit_text_callback),
       new TextKey("?", emit_text_callback),
-      new TextKey("del", delete_callback)};
+      delete_image_key};
 
   std::vector<Key*> symbols_key_map_row_four = {
       new TextKey("ABC", switch_to_lower_case_callback),
@@ -332,12 +405,12 @@
       new TextKey(" ", emit_text_callback),
       new TextKey("/", emit_text_callback),
       new TextKey(".", emit_text_callback),
-      new TextKey("act", do_nothing_callback)};
+      action_image_key};
 
   symbols_key_map_ = {symbols_key_map_row_one,
                       symbols_key_map_row_two,
                       symbols_key_map_row_three,
                       symbols_key_map_row_four};
 }
-
-}  // namespace keyboard
+}
+// namespace keyboard
diff --git a/services/keyboard_native/key_layout.h b/services/keyboard_native/key_layout.h
index d55e50f..09f5670 100644
--- a/services/keyboard_native/key_layout.h
+++ b/services/keyboard_native/key_layout.h
@@ -10,11 +10,15 @@
 
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
-#include "mojo/public/cpp/bindings/callback.h"
 #include "mojo/services/geometry/public/interfaces/geometry.mojom.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect.h"
+
+class SkCanvas;
+class SkPaint;
+
+namespace gfx {
+class RectF;
+class Point;
+}
 
 namespace keyboard {
 
@@ -29,7 +33,7 @@
 
     // Draws the Key to the SkCanvas with the given SkPaint to the given Rect.
     virtual void Draw(SkCanvas* canvas,
-                      SkPaint paint,
+                      const SkPaint& paint,
                       const gfx::RectF& rect) = 0;
 
     // Converts the Key to its text representation.
@@ -39,6 +43,8 @@
     virtual void OnTouchUp() = 0;
   };
 
+  class TextKey;
+
   KeyLayout();
   ~KeyLayout();
 
@@ -63,23 +69,6 @@
   void OnTouchUp(const gfx::Point& touch_up);
 
  private:
-  // An implementation of Key that draws itself as ASCII text.
-  class TextKey : public Key {
-   public:
-    TextKey(const char* text,
-            base::Callback<void(const TextKey&)> touch_up_callback);
-    ~TextKey() override;
-    void Draw(SkCanvas* canvas, SkPaint paint, const gfx::RectF& rect) override;
-    const char* ToText() const override;
-    void OnTouchUp() override;
-
-   private:
-    const char* text_;
-    base::Callback<void(const TextKey&)> touch_up_callback_;
-
-    DISALLOW_COPY_AND_ASSIGN(TextKey);
-  };
-
   // initializes the *_layout_ vectors.
   void InitLayouts();
 
diff --git a/services/keyboard_native/res/ArrowDown.png.sha1 b/services/keyboard_native/res/ArrowDown.png.sha1
new file mode 100644
index 0000000..3e06b96
--- /dev/null
+++ b/services/keyboard_native/res/ArrowDown.png.sha1
@@ -0,0 +1 @@
+d3830dc79ffbf9a5bc326049a9bf59d3f3426a9f
diff --git a/services/keyboard_native/res/ArrowUp.png.sha1 b/services/keyboard_native/res/ArrowUp.png.sha1
new file mode 100644
index 0000000..cb75efb
--- /dev/null
+++ b/services/keyboard_native/res/ArrowUp.png.sha1
@@ -0,0 +1 @@
+d6159c1f708c302b944a50e4dd6f6f727d0a7dc1
diff --git a/services/keyboard_native/res/Delete.png.sha1 b/services/keyboard_native/res/Delete.png.sha1
new file mode 100644
index 0000000..b281e11
--- /dev/null
+++ b/services/keyboard_native/res/Delete.png.sha1
@@ -0,0 +1 @@
+a380fa3bd13eec30a934eecde7b7266c5e9e0963
diff --git a/services/keyboard_native/res/Emoticon.png.sha1 b/services/keyboard_native/res/Emoticon.png.sha1
new file mode 100644
index 0000000..617bbd4
--- /dev/null
+++ b/services/keyboard_native/res/Emoticon.png.sha1
@@ -0,0 +1 @@
+00038b6305c221dd1670ce93b6e358f4a5211d33
diff --git a/services/keyboard_native/view_observer_delegate.cc b/services/keyboard_native/view_observer_delegate.cc
index aaec615..03016e5 100644
--- a/services/keyboard_native/view_observer_delegate.cc
+++ b/services/keyboard_native/view_observer_delegate.cc
@@ -15,6 +15,7 @@
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkTypeface.h"
+#include "ui/gfx/geometry/rect_f.h"
 
 namespace keyboard {