pw_framebuffer: Add row bytes member.

Add a row bytes framebuffer attribute as some framebuffers have
row padding resulting in the row bytes being greater than
pixel_size * width.

Change-Id: I6f19828841155995681696e15e8072ea3d419cc4
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/experimental/+/115372
Reviewed-by: Anthony DiGirolamo <tonymd@google.com>
Reviewed-by: Erik Gilling <konkers@google.com>
Commit-Queue: Chris Mumford <cmumford@google.com>
diff --git a/pw_graphics/pw_display_host_imgui/display.cc b/pw_graphics/pw_display_host_imgui/display.cc
index a8920c5..64ec1da 100644
--- a/pw_graphics/pw_display_host_imgui/display.cc
+++ b/pw_graphics/pw_display_host_imgui/display.cc
@@ -396,8 +396,10 @@
 }
 
 Status Display::InitFramebuffer(FramebufferRgb565* framebuffer) {
-  framebuffer->SetFramebufferData(
-      framebuffer_data, kDisplayWidth, kDisplayHeight);
+  framebuffer->SetFramebufferData(framebuffer_data,
+                                  kDisplayWidth,
+                                  kDisplayHeight,
+                                  kDisplayWidth * sizeof(uint16_t));
   return OkStatus();
 }
 
diff --git a/pw_graphics/pw_display_pico_ili9341/display.cc b/pw_graphics/pw_display_pico_ili9341/display.cc
index 2b881c2..05e5702 100644
--- a/pw_graphics/pw_display_pico_ili9341/display.cc
+++ b/pw_graphics/pw_display_pico_ili9341/display.cc
@@ -98,8 +98,10 @@
   }
 
   Status InitFramebuffer(pw::framebuffer::FramebufferRgb565* framebuffer) {
-    framebuffer->SetFramebufferData(
-        framebuffer_data_, kDisplayWidth, kDisplayHeight);
+    framebuffer->SetFramebufferData(framebuffer_data_,
+                                    kDisplayWidth,
+                                    kDisplayHeight,
+                                    kDisplayWidth * sizeof(uint16_t));
     return OkStatus();
   }
 
diff --git a/pw_graphics/pw_display_pico_st7789_spi/display.cc b/pw_graphics/pw_display_pico_st7789_spi/display.cc
index a15fbc8..b2ef3b6 100644
--- a/pw_graphics/pw_display_pico_st7789_spi/display.cc
+++ b/pw_graphics/pw_display_pico_st7789_spi/display.cc
@@ -344,8 +344,10 @@
 }
 
 Status Display::InitFramebuffer(FramebufferRgb565* framebuffer) {
-  framebuffer->SetFramebufferData(
-      framebuffer_data, kDisplayWidth, kDisplayHeight);
+  framebuffer->SetFramebufferData(framebuffer_data,
+                                  kDisplayWidth,
+                                  kDisplayHeight,
+                                  kDisplayWidth * sizeof(uint16_t));
   return OkStatus();
 }
 
diff --git a/pw_graphics/pw_display_stm32f429i_disc1_stm32cube_ili9341/display.cc b/pw_graphics/pw_display_stm32f429i_disc1_stm32cube_ili9341/display.cc
index bc30469..da634c8 100644
--- a/pw_graphics/pw_display_stm32f429i_disc1_stm32cube_ili9341/display.cc
+++ b/pw_graphics/pw_display_stm32f429i_disc1_stm32cube_ili9341/display.cc
@@ -106,8 +106,10 @@
 }
 
 Status Display::InitFramebuffer(FramebufferRgb565* framebuffer) {
-  framebuffer->SetFramebufferData(
-      framebuffer_data_, kDisplayWidth, kDisplayHeight);
+  framebuffer->SetFramebufferData(framebuffer_data_,
+                                  kDisplayWidth,
+                                  kDisplayHeight,
+                                  kDisplayWidth * sizeof(uint16_t));
   return OkStatus();
 }
 
diff --git a/pw_graphics/pw_display_teensy_ili9341/display.cc b/pw_graphics/pw_display_teensy_ili9341/display.cc
index 44287cd..660a72e 100644
--- a/pw_graphics/pw_display_teensy_ili9341/display.cc
+++ b/pw_graphics/pw_display_teensy_ili9341/display.cc
@@ -80,8 +80,10 @@
 }
 
 Status Display::InitFramebuffer(FramebufferRgb565* framebuffer) {
-  framebuffer->SetFramebufferData(
-      framebuffer_data, kDisplayWidth, kDisplayHeight);
+  framebuffer->SetFramebufferData(framebuffer_data,
+                                  kDisplayWidth,
+                                  kDisplayHeight,
+                                  kDisplayWidth * sizeof(uint16_t));
   return OkStatus();
 }
 
diff --git a/pw_graphics/pw_draw/draw_test.cc b/pw_graphics/pw_draw/draw_test.cc
index fe7f435..03222ba 100644
--- a/pw_graphics/pw_draw/draw_test.cc
+++ b/pw_graphics/pw_draw/draw_test.cc
@@ -67,7 +67,7 @@
 
 TEST(DrawLine, Diagonal) {
   uint16_t data[4 * 4];
-  FramebufferRgb565 fb(data, 4, 4);
+  FramebufferRgb565 fb(data, 4, 4, 4 * sizeof(data[0]));
   color_rgb565_t indigo = color::colors_pico8_rgb565[12];
 
   fb.Fill(0);
@@ -92,7 +92,7 @@
 
 TEST(DrawHLine, Top) {
   uint16_t data[4 * 4];
-  FramebufferRgb565 fb(data, 4, 4);
+  FramebufferRgb565 fb(data, 4, 4, 4 * sizeof(data[0]));
   color_rgb565_t indigo = color::colors_pico8_rgb565[12];
   fb.Fill(0);
 
@@ -114,7 +114,7 @@
 
 TEST(DrawRect, Empty) {
   uint16_t data[5 * 5];
-  FramebufferRgb565 fb(data, 5, 5);
+  FramebufferRgb565 fb(data, 5, 5, 5 * sizeof(data[0]));
   color_rgb565_t indigo = color::colors_pico8_rgb565[12];
   fb.Fill(0);
 
@@ -206,7 +206,7 @@
 
 TEST(DrawRect, Filled) {
   uint16_t data[5 * 5];
-  FramebufferRgb565 fb(data, 5, 5);
+  FramebufferRgb565 fb(data, 5, 5, 5 * sizeof(data[0]));
   color_rgb565_t indigo = color::colors_pico8_rgb565[12];
   fb.Fill(0);
 
@@ -293,7 +293,7 @@
 
 TEST(DrawRectWH, WidthHeightCorrect) {
   uint16_t data[5 * 5];
-  FramebufferRgb565 fb(data, 5, 5);
+  FramebufferRgb565 fb(data, 5, 5, 5 * sizeof(data[0]));
   color_rgb565_t indigo = color::colors_pico8_rgb565[12];
   fb.Fill(0);
 
@@ -385,7 +385,7 @@
 
 TEST(DrawCircle, Empty) {
   uint16_t data[7 * 7];
-  FramebufferRgb565 fb(data, 7, 7);
+  FramebufferRgb565 fb(data, 7, 7, 7 * sizeof(data[0]));
   color_rgb565_t indigo = color::colors_pico8_rgb565[12];
   fb.Fill(0);
 
@@ -559,7 +559,7 @@
 
 TEST(DrawText, WithFgBg) {
   uint16_t data[(5 * 6) * (3 * 8)];
-  FramebufferRgb565 fb(data, 5 * 6, 3 * 8);
+  FramebufferRgb565 fb(data, 5 * 6, 3 * 8, (5 * 6) * sizeof(data[0]));
   fb.Fill(0);
 
   pw::draw::TextArea text_area(&fb, &font6x8);
diff --git a/pw_graphics/pw_framebuffer/framebuffer_test.cc b/pw_graphics/pw_framebuffer/framebuffer_test.cc
index eba5eb9..11e0c75 100644
--- a/pw_graphics/pw_framebuffer/framebuffer_test.cc
+++ b/pw_graphics/pw_framebuffer/framebuffer_test.cc
@@ -28,14 +28,14 @@
 
 TEST(FramebufferRgb565, Init) {
   uint16_t data[32 * 32];
-  FramebufferRgb565 fb(data, 32, 32);
+  FramebufferRgb565 fb(data, 32, 32, 32 * sizeof(data[0]));
   EXPECT_EQ(fb.GetWidth(), 32);
   EXPECT_EQ(fb.GetHeight(), 32);
 }
 
 TEST(FramebufferRgb565, Fill) {
   uint16_t data[8 * 8];
-  FramebufferRgb565 fb(data, 8, 8);
+  FramebufferRgb565 fb(data, 8, 8, 8 * sizeof(data[0]));
   color_rgb565_t* const pixel_data = fb.GetFramebufferData();
   color_rgb565_t indigo = 0x83b3;
   fb.Fill(indigo);
@@ -47,7 +47,7 @@
 
 TEST(FramebufferRgb565, SetPixelGetPixel) {
   uint16_t data[8 * 8];
-  FramebufferRgb565 fb(data, 8, 8);
+  FramebufferRgb565 fb(data, 8, 8, 8 * sizeof(data[0]));
   color_rgb565_t* const pixel_data = fb.GetFramebufferData();
   color_rgb565_t indigo = 0x83b3;
   fb.Fill(0);
@@ -76,7 +76,7 @@
 
 TEST(FramebufferRgb565, Blit) {
   uint16_t data[8 * 8];
-  FramebufferRgb565 fb(data, 8, 8);
+  FramebufferRgb565 fb(data, 8, 8, 8 * sizeof(data[0]));
   color_rgb565_t indigo = color::colors_pico8_rgb565[12];
   fb.Fill(indigo);
   color_rgb565_t* const pixel_data = fb.GetFramebufferData();
@@ -86,7 +86,7 @@
   EXPECT_EQ(pixel_data[8 * 8 - 1], indigo);
 
   uint16_t data2[4 * 4];
-  FramebufferRgb565 fb2(data2, 4, 4);
+  FramebufferRgb565 fb2(data2, 4, 4, 4 * sizeof(data2[0]));
   color_rgb565_t orange = 0xfd00;
   fb2.Fill(orange);
 
diff --git a/pw_graphics/pw_framebuffer/public/pw_framebuffer/rgb565.h b/pw_graphics/pw_framebuffer/public/pw_framebuffer/rgb565.h
index c88946b..ba99498 100644
--- a/pw_graphics/pw_framebuffer/public/pw_framebuffer/rgb565.h
+++ b/pw_graphics/pw_framebuffer/public/pw_framebuffer/rgb565.h
@@ -28,7 +28,10 @@
   // Construct a framebuffer of the specified dimensions which *does not* own
   // the |data| - i.e. this instance may write to the data, but will never
   // attempt to free it.
-  FramebufferRgb565(pw::color::color_rgb565_t* data, int width, int height);
+  FramebufferRgb565(pw::color::color_rgb565_t* data,
+                    int width,
+                    int height,
+                    int row_bytes);
 
   FramebufferRgb565(const FramebufferRgb565&) = delete;
   FramebufferRgb565(FramebufferRgb565&& other) = delete;
@@ -43,7 +46,8 @@
 
   void SetFramebufferData(pw::color::color_rgb565_t* data,
                           int width,
-                          int height);
+                          int height,
+                          int row_bytes);
 
   // Return the RGB565 color at position x, y. Bounds are checked.
   Result<pw::color::color_rgb565_t> GetPixel(int x, int y) const;
@@ -63,12 +67,14 @@
   // Return framebuffer height in pixels.
   int GetHeight() const { return height_; }
 
+  // Return the number of bytes per row of pixel data.
+  int GetRowBytes() const { return row_bytes_; }
+
  private:
-  // TODO(tonymd): Add a stride variable. Right now width is being treated as
-  // the stride value.
   pw::color::color_rgb565_t* pixel_data_;
   int width_;
   int height_;
+  int row_bytes_;
 };
 
 }  // namespace pw::framebuffer
diff --git a/pw_graphics/pw_framebuffer/rgb565.cc b/pw_graphics/pw_framebuffer/rgb565.cc
index 7687607..fe8a45f 100644
--- a/pw_graphics/pw_framebuffer/rgb565.cc
+++ b/pw_graphics/pw_framebuffer/rgb565.cc
@@ -22,18 +22,24 @@
 namespace pw::framebuffer {
 
 FramebufferRgb565::FramebufferRgb565()
-    : pixel_data_(nullptr), width_(0), height_(0) {}
+    : pixel_data_(nullptr), width_(0), height_(0), row_bytes_(0) {}
 
 FramebufferRgb565::FramebufferRgb565(color_rgb565_t* data,
                                      int width,
-                                     int height)
-    : pixel_data_(data), width_(width), height_(height) {}
+                                     int height,
+                                     int row_bytes)
+    : pixel_data_(data),
+      width_(width),
+      height_(height),
+      row_bytes_(row_bytes) {}
 
 void FramebufferRgb565::SetFramebufferData(color_rgb565_t* data,
                                            int width,
-                                           int height) {
+                                           int height,
+                                           int row_bytes) {
   width_ = width;
   height_ = height;
+  row_bytes_ = row_bytes;
   pixel_data_ = data;
 }