summaryrefslogtreecommitdiffstats
path: root/gfx/2d/BufferEdgePad.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/2d/BufferEdgePad.cpp')
-rw-r--r--gfx/2d/BufferEdgePad.cpp104
1 files changed, 104 insertions, 0 deletions
diff --git a/gfx/2d/BufferEdgePad.cpp b/gfx/2d/BufferEdgePad.cpp
new file mode 100644
index 0000000000..69f508f788
--- /dev/null
+++ b/gfx/2d/BufferEdgePad.cpp
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "BufferEdgePad.h"
+
+#include "2D.h" // for DrawTarget
+#include "Point.h" // for IntSize
+#include "Types.h" // for SurfaceFormat
+
+#include "nsRegion.h"
+
+namespace mozilla {
+namespace gfx {
+
+void PadDrawTargetOutFromRegion(DrawTarget* aDrawTarget,
+ const nsIntRegion& aRegion) {
+ struct LockedBits {
+ uint8_t* data;
+ IntSize size;
+ int32_t stride;
+ SurfaceFormat format;
+ static int clamp(int x, int min, int max) {
+ if (x < min) x = min;
+ if (x > max) x = max;
+ return x;
+ }
+
+ static void ensure_memcpy(uint8_t* dst, uint8_t* src, size_t n,
+ uint8_t* bitmap, int stride, int height) {
+ if (src + n > bitmap + stride * height) {
+ MOZ_CRASH("GFX: long src memcpy");
+ }
+ if (src < bitmap) {
+ MOZ_CRASH("GFX: short src memcpy");
+ }
+ if (dst + n > bitmap + stride * height) {
+ MOZ_CRASH("GFX: long dst mempcy");
+ }
+ if (dst < bitmap) {
+ MOZ_CRASH("GFX: short dst mempcy");
+ }
+ }
+
+ static void visitor(void* closure, VisitSide side, int x1, int y1, int x2,
+ int y2) {
+ LockedBits* lb = static_cast<LockedBits*>(closure);
+ uint8_t* bitmap = lb->data;
+ const int bpp = gfx::BytesPerPixel(lb->format);
+ const int stride = lb->stride;
+ const int width = lb->size.width;
+ const int height = lb->size.height;
+
+ if (side == VisitSide::TOP) {
+ if (y1 > 0) {
+ x1 = clamp(x1, 0, width - 1);
+ x2 = clamp(x2, 0, width - 1);
+ ensure_memcpy(&bitmap[x1 * bpp + (y1 - 1) * stride],
+ &bitmap[x1 * bpp + y1 * stride], (x2 - x1) * bpp,
+ bitmap, stride, height);
+ memcpy(&bitmap[x1 * bpp + (y1 - 1) * stride],
+ &bitmap[x1 * bpp + y1 * stride], (x2 - x1) * bpp);
+ }
+ } else if (side == VisitSide::BOTTOM) {
+ if (y1 < height) {
+ x1 = clamp(x1, 0, width - 1);
+ x2 = clamp(x2, 0, width - 1);
+ ensure_memcpy(&bitmap[x1 * bpp + y1 * stride],
+ &bitmap[x1 * bpp + (y1 - 1) * stride], (x2 - x1) * bpp,
+ bitmap, stride, height);
+ memcpy(&bitmap[x1 * bpp + y1 * stride],
+ &bitmap[x1 * bpp + (y1 - 1) * stride], (x2 - x1) * bpp);
+ }
+ } else if (side == VisitSide::LEFT) {
+ if (x1 > 0) {
+ while (y1 != y2) {
+ memcpy(&bitmap[(x1 - 1) * bpp + y1 * stride],
+ &bitmap[x1 * bpp + y1 * stride], bpp);
+ y1++;
+ }
+ }
+ } else if (side == VisitSide::RIGHT) {
+ if (x1 < width) {
+ while (y1 != y2) {
+ memcpy(&bitmap[x1 * bpp + y1 * stride],
+ &bitmap[(x1 - 1) * bpp + y1 * stride], bpp);
+ y1++;
+ }
+ }
+ }
+ }
+ } lb;
+
+ if (aDrawTarget->LockBits(&lb.data, &lb.size, &lb.stride, &lb.format)) {
+ // we can only pad software targets so if we can't lock the bits don't pad
+ aRegion.VisitEdges(lb.visitor, &lb);
+ aDrawTarget->ReleaseBits(lb.data);
+ }
+}
+
+} // namespace gfx
+} // namespace mozilla