File: java_bitmap.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (174 lines) | stat: -rw-r--r-- 6,113 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gfx/android/java_bitmap.h"

#include <android/bitmap.h>

#include "base/android/jni_string.h"
#include "base/bits.h"
#include "base/check_op.h"
#include "base/debug/crash_logging.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "ui/gfx/geometry/size.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "ui/gfx/gfx_jni_headers/BitmapHelper_jni.h"

using base::android::ConvertUTF8ToJavaString;
using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
using jni_zero::AttachCurrentThread;

namespace jni_zero {

// Converts |bitmap| to an SkBitmap of the same size and format.
// Note: |j_bitmap| is assumed to be non-null, non-empty and of format
// RGBA_8888.
template <>
SkBitmap FromJniType<SkBitmap>(JNIEnv* env, const JavaRef<jobject>& j_bitmap) {
  return gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(j_bitmap));
}

// Converts |skbitmap| to a Java-backed bitmap (android.graphics.Bitmap).
// Note: return nullptr jobject if |skbitmap| is null or empty.
template <>
ScopedJavaLocalRef<jobject> ToJniType<SkBitmap>(JNIEnv* env,
                                                const SkBitmap& skbitmap) {
  if (skbitmap.drawsNothing()) {
    return {};
  }
  return gfx::ConvertToJavaBitmap(skbitmap, gfx::OomBehavior::kCrashOnOom);
}
}  // namespace jni_zero

namespace gfx {
namespace {

int SkColorTypeToBitmapFormat(SkColorType color_type) {
  switch (color_type) {
    case kN32_SkColorType:
      return BITMAP_FORMAT_ARGB_8888;
    case kRGB_565_SkColorType:
      return BITMAP_FORMAT_RGB_565;
    default:
      // A bad format can cause out-of-bounds issues when copying pixels into or
      // out of the java bitmap's pixel buffer.
      CHECK_NE(color_type, color_type);
  }
  return BITMAP_FORMAT_NO_CONFIG;
}

SkColorType BitmapFormatToSkColorType(BitmapFormat bitmap_format) {
  switch (bitmap_format) {
    case BITMAP_FORMAT_ALPHA_8:
      return kAlpha_8_SkColorType;
    case BITMAP_FORMAT_ARGB_4444:
      return kARGB_4444_SkColorType;
    case BITMAP_FORMAT_ARGB_8888:
      return kN32_SkColorType;
    case BITMAP_FORMAT_RGB_565:
      return kRGB_565_SkColorType;
    case BITMAP_FORMAT_NO_CONFIG:
    default:
      SCOPED_CRASH_KEY_NUMBER("gfx", "bitmap_format",
                              static_cast<int>(bitmap_format));
      CHECK_NE(bitmap_format, bitmap_format);
      return kUnknown_SkColorType;
  }
}

// Wraps a Java bitmap as an SkPixmap. Since the pixmap references the
// underlying pixel data in the Java bitmap directly, it is only valid as long
// as |bitmap| is.
SkPixmap WrapJavaBitmapAsPixmap(const JavaBitmap& bitmap) {
  auto color_type = BitmapFormatToSkColorType(bitmap.format());
  auto image_info =
      SkImageInfo::Make(bitmap.size().width(), bitmap.size().height(),
                        color_type, kPremul_SkAlphaType);
  return SkPixmap(image_info, bitmap.pixels(), bitmap.bytes_per_row());
}

}  // namespace

#define ASSERT_ENUM_EQ(a, b) \
  static_assert(static_cast<int>(a) == static_cast<int>(b), "")

// BitmapFormat has the same values as AndroidBitmapFormat, for simplicitly, so
// that SkColorTypeToBitmapFormat() and the JavaBitmap::format() have the same
// values.
ASSERT_ENUM_EQ(BITMAP_FORMAT_NO_CONFIG, ANDROID_BITMAP_FORMAT_NONE);
ASSERT_ENUM_EQ(BITMAP_FORMAT_ALPHA_8, ANDROID_BITMAP_FORMAT_A_8);
ASSERT_ENUM_EQ(BITMAP_FORMAT_ARGB_4444, ANDROID_BITMAP_FORMAT_RGBA_4444);
ASSERT_ENUM_EQ(BITMAP_FORMAT_ARGB_8888, ANDROID_BITMAP_FORMAT_RGBA_8888);
ASSERT_ENUM_EQ(BITMAP_FORMAT_RGB_565, ANDROID_BITMAP_FORMAT_RGB_565);

JavaBitmap::JavaBitmap(const JavaRef<jobject>& bitmap) : bitmap_(bitmap) {
  int err = AndroidBitmap_lockPixels(AttachCurrentThread(), bitmap_.obj(),
                                     &pixels_.AsEphemeralRawAddr());
  DCHECK(!err);
  DCHECK(pixels_);

  AndroidBitmapInfo info;
  err = AndroidBitmap_getInfo(AttachCurrentThread(), bitmap_.obj(), &info);
  DCHECK(!err);
  size_ = gfx::Size(info.width, info.height);
  format_ = static_cast<BitmapFormat>(info.format);
  bytes_per_row_ = info.stride;
  byte_count_ = Java_BitmapHelper_getByteCount(AttachCurrentThread(), bitmap_);
}

JavaBitmap::~JavaBitmap() {
  int err = AndroidBitmap_unlockPixels(AttachCurrentThread(), bitmap_.obj());
  DCHECK(!err);
}

ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(const SkBitmap& skbitmap,
                                                OomBehavior reaction) {
  DCHECK(!skbitmap.isNull());
  DCHECK_GT(skbitmap.width(), 0);
  DCHECK_GT(skbitmap.height(), 0);

  int java_bitmap_format = SkColorTypeToBitmapFormat(skbitmap.colorType());

  ScopedJavaLocalRef<jobject> jbitmap = Java_BitmapHelper_createBitmap(
      AttachCurrentThread(), skbitmap.width(), skbitmap.height(),
      java_bitmap_format, reaction == OomBehavior::kReturnNullOnOom);
  if (!jbitmap) {
    DCHECK_EQ(OomBehavior::kReturnNullOnOom, reaction);
    return jbitmap;
  }

  JavaBitmap dst_lock(jbitmap);
  SkPixmap dst = WrapJavaBitmapAsPixmap(dst_lock);
  skbitmap.readPixels(dst);
  return jbitmap;
}

SkBitmap CreateSkBitmapFromJavaBitmap(const JavaBitmap& jbitmap) {
  DCHECK(!jbitmap.size().IsEmpty());
  DCHECK_GT(jbitmap.bytes_per_row(), 0U);
  DCHECK(jbitmap.pixels());

  // Ensure 4 byte stride alignment since the texture upload code in the
  // compositor relies on this.
  SkPixmap src = WrapJavaBitmapAsPixmap(jbitmap);
  const size_t min_row_bytes = src.info().minRowBytes();
  const size_t row_bytes = base::bits::AlignUp(min_row_bytes, size_t{4});

  SkBitmap skbitmap;
  skbitmap.allocPixels(src.info(), row_bytes);
  skbitmap.writePixels(src);
  return skbitmap;
}

SkColorType ConvertToSkiaColorType(const JavaRef<jobject>& bitmap_config) {
  BitmapFormat jbitmap_format =
      static_cast<BitmapFormat>(Java_BitmapHelper_getBitmapFormatForConfig(
          AttachCurrentThread(), bitmap_config));
  return BitmapFormatToSkColorType(jbitmap_format);
}

}  //  namespace gfx