1 /* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 */ 4 #include "config.h" 5 6 #include "BufferImageJava.h" 7 #include <wtf/text/CString.h> 8 #include "GraphicsContext.h" 9 #include "ImageBuffer.h" 10 #include "ImageData.h" 11 #include "MIMETypeRegistry.h" 12 #include "NotImplemented.h" 13 14 #include "PlatformContextJava.h" 15 #include "GraphicsContext.h" 16 #include "IntRect.h" //XXX: recheck 17 #include "ImageBufferData.h" 18 19 20 21 namespace WebCore { 22 23 ImageBufferData::ImageBufferData( 24 const FloatSize& size, 25 ImageBuffer &rq_holder 26 ) : m_rq_holder(rq_holder) 27 { 28 JNIEnv* env = WebCore_GetJavaEnv(); 29 30 static jmethodID midCreateImage = env->GetMethodID( 31 PG_GetGraphicsManagerClass(env), 32 "createRTImage", 33 "(II)Lcom/sun/webkit/graphics/WCImage;"); 34 ASSERT(midCreateImage); 35 36 m_image = RQRef::create(JLObject(env->CallObjectMethod( 37 PL_GetGraphicsManager(env), 38 midCreateImage, 39 (jint) size.width(), 40 (jint) size.height() 41 ))); 42 CheckAndClearException(env); 43 } 44 45 JLObject ImageBufferData::getWCImage() const 46 { 47 return m_image->cloneLocalCopy(); 48 } 49 50 unsigned char *ImageBufferData::data() const 51 { 52 JNIEnv* env = WebCore_GetJavaEnv(); 53 54 //RenderQueue need to be processed before pixel buffer extraction. 55 //For that purpose it has to be in actual state. 56 m_rq_holder.context()->platformContext()->rq().flushBuffer(); 57 58 static jmethodID midGetBGRABytes = env->GetMethodID( 59 PG_GetImageClass(env), 60 "getPixelBuffer", 61 "()Ljava/nio/ByteBuffer;"); 62 ASSERT(midGetBGRABytes); 63 64 JLObject byteBuffer(env->CallObjectMethod(getWCImage(), midGetBGRABytes)); 65 CheckAndClearException(env); 66 67 return byteBuffer 68 ? (unsigned char *) env->GetDirectBufferAddress(byteBuffer) 69 : NULL; 70 } 71 72 void ImageBufferData::update() 73 { 74 JNIEnv* env = WebCore_GetJavaEnv(); 75 76 static jmethodID midUpdateByteBuffer = env->GetMethodID( 77 PG_GetImageClass(env), 78 "drawPixelBuffer", 79 "()V"); 80 ASSERT(midUpdateByteBuffer); 81 82 env->CallObjectMethod(getWCImage(), midUpdateByteBuffer); 83 CheckAndClearException(env); 84 } 85 86 ImageBuffer::ImageBuffer( 87 const FloatSize& size, 88 float resolutionScale, 89 ColorSpace, 90 RenderingMode, 91 bool& success 92 ) 93 : m_data(size, *this) 94 , m_resolutionScale(1) 95 { 96 // RT-10059: ImageBufferData construction may fail if the requested 97 // image size is too large. In that case we exit immediately, 98 // automatically reporting the failure to ImageBuffer::create(). 99 if (!m_data.m_image) { 100 return; 101 } 102 103 float scaledWidth = ceilf(resolutionScale * size.width()); 104 float scaledHeight = ceilf(resolutionScale * size.height()); 105 106 // FIXME: Should we automatically use a lower resolution? //XXX: copy-paste from ImageBufferCG.cpp 107 if (!FloatSize(scaledWidth, scaledHeight).isExpressibleAsIntSize()) 108 return; 109 110 m_size = IntSize(scaledWidth, scaledHeight); 111 m_logicalSize = IntSize(scaledWidth, scaledHeight); 112 113 JNIEnv* env = WebCore_GetJavaEnv(); 114 static jmethodID midCreateBufferedContextRQ = env->GetMethodID( 115 PG_GetGraphicsManagerClass(env), 116 "createBufferedContextRQ", 117 "(Lcom/sun/webkit/graphics/WCImage;)Lcom/sun/webkit/graphics/WCRenderQueue;"); 118 ASSERT(midCreateBufferedContextRQ); 119 120 JLObject wcRenderQueue(env->CallObjectMethod( 121 PL_GetGraphicsManager(env), 122 midCreateBufferedContextRQ, 123 (jobject)m_data.getWCImage())); 124 ASSERT(wcRenderQueue); 125 CheckAndClearException(env); 126 127 m_data.m_context = std::make_unique<GraphicsContext>(new PlatformContextJava(wcRenderQueue, true)); 128 success = true; 129 } 130 131 ImageBuffer::~ImageBuffer() 132 { 133 } 134 135 /* 136 size_t ImageBuffer::dataSize() const 137 { 138 return m_size.width() * m_size.height() * 4; 139 } 140 */ 141 142 GraphicsContext* ImageBuffer::context() const 143 { 144 return m_data.m_context.get(); 145 } 146 147 RefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior scaleBehavior) const 148 { 149 //utatodo: seems [copyBehavior] is the rest of [drawsUsingCopy] 150 return BufferImage::create( 151 m_data.m_image, 152 m_data.m_context->platformContext()->rq_ref(), 153 m_size.width(), m_size.height()); 154 } 155 156 BackingStoreCopy ImageBuffer::fastCopyImageMode() 157 { 158 return CopyBackingStore; // todo tav revise 159 } 160 161 void ImageBuffer::platformTransformColorSpace(const Vector<int> &lookUpTable) 162 { 163 notImplemented(); 164 /* 165 uint8* rowData = reinterpret_cast<uint8*>(m_data.m_bitmap.Bits()); 166 unsigned bytesPerRow = m_data.m_bitmap.BytesPerRow(); 167 unsigned rows = m_size.height(); 168 unsigned columns = m_size.width(); 169 for (unsigned y = 0; y < rows; y++) { 170 uint8* pixel = rowData; 171 for (unsigned x = 0; x < columns; x++) { 172 // lookUpTable doesn't seem to support a LUT for each color channel 173 // separately (judging from the other ports). We don't need to 174 // convert from/to pre-multiplied color space since BBitmap storage 175 // is not pre-multiplied. 176 pixel[0] = lookUpTable[pixel[0]]; 177 pixel[1] = lookUpTable[pixel[1]]; 178 pixel[2] = lookUpTable[pixel[2]]; 179 // alpha stays unmodified. 180 pixel += 4; 181 } 182 rowData += bytesPerRow; 183 } 184 */ 185 } 186 187 PassRefPtr<Uint8ClampedArray> getImageData( 188 const Multiply multiplied, 189 const ImageBufferData &idata, 190 const IntRect& rect, 191 const IntSize& size) 192 { 193 // This code was adapted from the CG implementation 194 195 float area = 4.0f * rect.width() * rect.height(); 196 if (area > static_cast<float>(std::numeric_limits<int>::max())) 197 return 0; 198 199 RefPtr<Uint8ClampedArray> result = Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4); 200 unsigned char* data = result->data(); 201 202 if (rect.x() < 0 || rect.y() < 0 203 || rect.maxX() > size.width() || rect.maxY() > size.height()) 204 result->zeroFill(); 205 206 int originx = rect.x(); 207 int destx = 0; 208 if (originx < 0) { 209 destx = -originx; 210 originx = 0; 211 } 212 int endx = rect.maxX(); 213 if (endx > size.width()) 214 endx = size.width(); 215 int width = endx - originx; 216 217 int originy = rect.y(); 218 int desty = 0; 219 if (originy < 0) { 220 desty = -originy; 221 originy = 0; 222 } 223 int endy = rect.maxY(); 224 if (endy > size.height()) 225 endy = size.height(); 226 int height = endy - originy; 227 228 if (width <= 0 || height <= 0) 229 return result; 230 231 unsigned dstBytesPerRow = 4 * rect.width(); 232 unsigned char* dstRows = data + desty * dstBytesPerRow + destx * 4; 233 234 unsigned srcBytesPerRow = 4 * size.width(); 235 unsigned char* srcRows = 236 idata.data() + originy * srcBytesPerRow + originx * 4; 237 238 for (int y = 0; y < height; ++y) { 239 unsigned char *pd = dstRows; 240 unsigned char *ps = srcRows; 241 for (int x = 0; x < width; x++) { 242 unsigned char alpha = ps[3]; 243 if (multiplied == Unmultiplied && alpha && alpha!=255) { 244 // Unmultiply and convert BGRA to RGBA 245 pd[0] = (ps[2] * 255) / alpha; 246 pd[1] = (ps[1] * 255) / alpha; 247 pd[2] = (ps[0] * 255) / alpha; 248 pd[3] = alpha; 249 } else { 250 // Convert BGRA to RGBA 251 pd[0] = ps[2]; 252 pd[1] = ps[1]; 253 pd[2] = ps[0]; 254 pd[3] = alpha; 255 } 256 pd += 4; 257 ps += 4; 258 } 259 srcRows += srcBytesPerRow; 260 dstRows += dstBytesPerRow; 261 } 262 263 264 return result; 265 } 266 267 PassRefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, CoordinateSystem) const 268 { 269 return getImageData(Unmultiplied, m_data, rect, m_size); 270 } 271 272 PassRefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, CoordinateSystem) const 273 { 274 return getImageData(Premultiplied, m_data, rect, m_size); 275 } 276 277 void ImageBuffer::putByteArray( 278 Multiply multiplied, 279 Uint8ClampedArray* source, 280 const IntSize& sourceSize, 281 const IntRect& sourceRect, 282 const IntPoint& destPoint, 283 CoordinateSystem) 284 { 285 // This code was adapted from the CG implementation 286 287 ASSERT(sourceRect.width() > 0); 288 ASSERT(sourceRect.height() > 0); 289 290 int originx = sourceRect.x(); 291 int destx = destPoint.x() + sourceRect.x(); 292 ASSERT(destx >= 0); 293 ASSERT(destx < m_size.width()); 294 ASSERT(originx >= 0); 295 ASSERT(originx <= sourceRect.maxX()); 296 297 int endx = destPoint.x() + sourceRect.maxX(); 298 ASSERT(endx <= m_size.width()); 299 int width = endx - destx; 300 301 int originy = sourceRect.y(); 302 int desty = destPoint.y() + sourceRect.y(); 303 ASSERT(desty >= 0); 304 ASSERT(desty < m_size.height()); 305 ASSERT(originy >= 0); 306 ASSERT(originy <= sourceRect.maxY()); 307 308 int endy = destPoint.y() + sourceRect.maxY(); 309 ASSERT(endy <= m_size.height()); 310 int height = endy - desty; 311 312 if (width <= 0 || height <= 0) 313 return; 314 315 unsigned srcBytesPerRow = 4 * sourceSize.width(); 316 unsigned char* srcRows = 317 source->data() + originy * srcBytesPerRow + originx * 4; 318 unsigned dstBytesPerRow = 4 * m_size.width(); 319 unsigned char* dstRows = 320 m_data.data() + desty * dstBytesPerRow + destx * 4; 321 322 for (int y = 0; y < height; ++y) { 323 unsigned char *pd = dstRows; 324 unsigned char *ps = srcRows; 325 for (int x = 0; x < width; x++) { 326 int alpha = ps[3]; //have to be [int] for right multiply casting 327 if (multiplied == Unmultiplied && alpha != 255) { 328 // Premultiply and convert RGBA to BGRA 329 pd[0] = static_cast<unsigned char>((ps[2] * alpha + 254) / 255); 330 pd[1] = static_cast<unsigned char>((ps[1] * alpha + 254) / 255); 331 pd[2] = static_cast<unsigned char>((ps[0] * alpha + 254) / 255); 332 pd[3] = static_cast<unsigned char>(alpha); 333 } else { 334 // Convert RGBA to BGRA 335 pd[0] = ps[2]; 336 pd[1] = ps[1]; 337 pd[2] = ps[0]; 338 pd[3] = alpha; 339 } 340 pd += 4; 341 ps += 4; 342 } 343 dstRows += dstBytesPerRow; 344 srcRows += srcBytesPerRow; 345 } 346 347 m_data.update(); 348 } 349 350 void ImageBuffer::clip(GraphicsContext*, const FloatRect&) const 351 { 352 notImplemented(); 353 } 354 355 void ImageBuffer::draw( 356 GraphicsContext* context, 357 ColorSpace styleColorSpace, 358 const FloatRect& destRect, 359 const FloatRect& srcRect, 360 CompositeOperator op, 361 BlendMode bm, 362 bool useLowQualityScale) 363 { 364 RefPtr<Image> imageCopy = copyImage(); 365 context->drawImage( 366 imageCopy.get(), 367 styleColorSpace, 368 destRect, 369 srcRect, 370 ImagePaintingOptions( 371 op, 372 bm, 373 DoNotRespectImageOrientation, 374 useLowQualityScale) 375 ); 376 } 377 378 void ImageBuffer::drawPattern( 379 GraphicsContext* context, 380 const FloatRect& srcRect, 381 const AffineTransform& patternTransform, 382 const FloatPoint& phase, 383 ColorSpace styleColorSpace, 384 CompositeOperator op, 385 const FloatRect& destRect, 386 BlendMode bm) // todo tav new param 387 { 388 RefPtr<Image> imageCopy = copyImage(); 389 imageCopy->drawPattern( 390 context, 391 srcRect, 392 patternTransform, 393 phase, 394 styleColorSpace, 395 op, 396 destRect); 397 } 398 399 String ImageBuffer::toDataURL(const String& mimeType, const double* quality, CoordinateSystem) const 400 { 401 if (MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)) { 402 //RenderQueue need to be processed before pixel buffer extraction. 403 //For that purpose it has to be in actual state. 404 context()->platformContext()->rq().flushBuffer(); 405 406 JNIEnv* env = WebCore_GetJavaEnv(); 407 408 static jmethodID midToDataURL = env->GetMethodID( 409 PG_GetImageClass(env), 410 "toDataURL", 411 "(Ljava/lang/String;)Ljava/lang/String;"); 412 ASSERT(midToDataURL); 413 414 JLString data((jstring) env->CallObjectMethod( 415 m_data.getWCImage(), 416 midToDataURL, 417 (jstring) JLString(mimeType.toJavaString(env)))); 418 419 CheckAndClearException(env); 420 if (data) { 421 return String(env, data); 422 } 423 } 424 return "data:,"; 425 } 426 427 }