Add --offset <x,y> for playing animation on specified location

When displaying messages, we need to play animation on top of prepared large
background image.  Since these images are centered in screen, --location does
not work (frame buffer size is unknown to caller) and --offset will be easier
for startup scripts to use.

BUG=chromium-os:21214
TEST=display_boot_message enter_dev1 en  # image centering still works
     ply-image --offset -300,0 /usr/share/chromeos-assets/images/*frame*
     # seeing animation played in -300 pixels from center

Change-Id: I2906d1406ee113ee3cfabfb700017ab7314f480f
Reviewed-on: http://gerrit.chromium.org/gerrit/9926
Reviewed-by: Richard Barnette <jrbarnette@chromium.org>
Reviewed-by: Daniel Erat <derat@chromium.org>
Tested-by: Hung-Te Lin <hungte@chromium.org>
diff --git a/src/ply-frame-buffer.c b/src/ply-frame-buffer.c
index 4d7207a..8a3af61 100644
--- a/src/ply-frame-buffer.c
+++ b/src/ply-frame-buffer.c
@@ -610,27 +610,6 @@
 }
 
 
-/*
- * Fill the given frame buffer with the given image data.  The
- * image will be centered in the frame buffer based on the width
- * and height in the given area.
- *
- * Returns true if any part of the image was copied.  Returns false
- * if any condition (e.g. clipping) caused the entire image to be
- * skipped.
- */
-bool ply_frame_buffer_fill_centered(ply_frame_buffer_t *buffer,
-                                    ply_frame_buffer_area_t *area,
-                                    uint32_t *data) {
-  assert(buffer != NULL);
-  assert(area != NULL);
-
-  area->x = (long) (buffer->area.width - area->width) / 2;
-  area->y = (long) (buffer->area.height - area->height) / 2;
-  return ply_frame_buffer_fill(buffer, area, data);
-}
-
-
 const char *ply_frame_buffer_get_bytes(ply_frame_buffer_t *buffer) {
   return (char *) buffer->shadow_buffer;
 }
diff --git a/src/ply-frame-buffer.h b/src/ply-frame-buffer.h
index 7e5f1b8..c18a399 100644
--- a/src/ply-frame-buffer.h
+++ b/src/ply-frame-buffer.h
@@ -53,9 +53,6 @@
 bool ply_frame_buffer_fill(ply_frame_buffer_t *buffer,
                            ply_frame_buffer_area_t *area,
                            uint32_t *data);
-bool ply_frame_buffer_fill_centered(ply_frame_buffer_t *buffer,
-                                    ply_frame_buffer_area_t *area,
-                                    uint32_t *data);
 void ply_frame_buffer_clear(ply_frame_buffer_t *buffer,
                             uint32_t clear_color);
 
diff --git a/src/ply-image.c b/src/ply-image.c
index d4ceee5..f98901c 100644
--- a/src/ply-image.c
+++ b/src/ply-image.c
@@ -248,14 +248,14 @@
 }
 
 static bool center_image = true;
-static ply_frame_buffer_area_t image_location;
+static ply_frame_buffer_area_t image_location, image_offset;
 static uint32_t clear_color;
 
 static void ply_frame_buffer_show_file(
     ply_frame_buffer_t *buffer, const char *path) {
   ply_image_t *image;
   uint32_t *data;
-  ply_frame_buffer_area_t area;
+  ply_frame_buffer_area_t area, buffer_area;
   bool fill_succeeded;
 
   image = ply_image_from_file(path);
@@ -265,13 +265,18 @@
   data = ply_image_get_data(image);
 
   if (center_image) {
-    fill_succeeded = ply_frame_buffer_fill_centered(buffer, &area, data);
+    ply_frame_buffer_get_size(buffer, &buffer_area);
+    area.x = (long) (buffer_area.width - area.width) / 2;
+    area.y = (long) (buffer_area.height - area.height) / 2;
   } else {
     area.x = image_location.x;
     area.y = image_location.y;
-    fill_succeeded = ply_frame_buffer_fill(buffer, &area, data);
   }
 
+  area.x += image_offset.x;
+  area.y += image_offset.y;
+  fill_succeeded = ply_frame_buffer_fill(buffer, &area, data);
+
   if (!fill_succeeded)
     fprintf(stderr, "image was not displayed\n");
 
@@ -283,7 +288,8 @@
   fprintf(stderr,
           "usage: ply-image --clear <hexcolor>\n"
           "       ply-image [--gamma <gammafile>] "
-          "[--location <x>,<y>] <frame> [<frame> ...]\n");
+          "[--location <x>,<y> | --offset <[+|-]x>,<[+|-]y>] "
+          "<frame> [<frame> ...]\n");
   exit(EXIT_FAILURE);
 }
 
@@ -299,24 +305,38 @@
   return true;
 }
 
-static bool parse_location(const char *arg) {
+static bool parse_xy(const char *arg, ply_frame_buffer_area_t *area) {
   char *endptr;
+  long x, y;
 
-  image_location.x = strtol(arg, &endptr, 10);
+  x = strtol(arg, &endptr, 10);
   if (endptr == arg || *endptr != ',') {
     return false;
   }
 
   arg = endptr + 1;
-  image_location.y = strtol(arg, &endptr, 10);
+  y = strtol(arg, &endptr, 10);
   if (endptr == arg || *endptr != '\0') {
     return false;
   }
 
-  center_image = false;
+  area->x = x;
+  area->y = y;
+
   return true;
 }
 
+static bool parse_location(const char *arg) {
+  bool result = parse_xy(arg, &image_location);
+  if (result)
+    center_image = false;
+  return result;
+}
+
+static bool parse_offset(const char *arg) {
+  return parse_xy(arg, &image_offset);
+}
+
 
 #define MS_PER_SEC      1000
 #define NS_PER_SEC      (1000 * 1000 * 1000)
@@ -379,6 +399,7 @@
 #define FLAG_GAMMA      'g'
 #define FLAG_HELP       'h'
 #define FLAG_LOCATION   'l'
+#define FLAG_OFFSET     'o'
 
 static struct option command_options[] = {
   { "clear", required_argument, NULL, FLAG_CLEAR },
@@ -386,12 +407,14 @@
   { "gamma", required_argument, NULL, FLAG_GAMMA },
   { "help", no_argument, NULL, FLAG_HELP },
   { "location", required_argument, NULL, FLAG_LOCATION },
+  { "offset", required_argument, NULL, FLAG_OFFSET },
   { NULL, 0, NULL, 0 },
 };
 
 
 int main(int argc, char **argv) {
   int clear = 0;
+  bool location_assigned = false, offset_assigned = false;
   ply_frame_buffer_t *buffer;
 
   /*
@@ -439,8 +462,23 @@
       if (!parse_location(optarg)) {
         usage();
       }
+      location_assigned = true;
       continue;
     }
+
+    if (c == FLAG_OFFSET) {
+      if (!parse_offset(optarg)) {
+        usage();
+      }
+      offset_assigned = true;
+      continue;
+    }
+  }
+
+  if (location_assigned && offset_assigned) {
+    fprintf(stderr,
+            "--location and --offset should not be assigned at same time.\n");
+    usage();
   }
 
   buffer = ply_frame_buffer_new(NULL);