| OLD | NEW | 
 | (Empty) | 
|    1 // Copyright 2016 The Chromium Authors. All rights reserved. |  | 
|    2 // Use of this source code is governed by a BSD-style license that can be |  | 
|    3 // found in the LICENSE file. |  | 
|    4  |  | 
|    5 #include "blimp/engine/renderer/engine_image_serialization_processor.h" |  | 
|    6  |  | 
|    7 #include <stddef.h> |  | 
|    8 #include <set> |  | 
|    9 #include <string> |  | 
|   10 #include <vector> |  | 
|   11  |  | 
|   12 #include "base/lazy_instance.h" |  | 
|   13 #include "base/logging.h" |  | 
|   14 #include "base/memory/ptr_util.h" |  | 
|   15 #include "base/strings/string_number_conversions.h" |  | 
|   16 #include "base/trace_event/trace_event.h" |  | 
|   17 #include "blimp/common/blob_cache/id_util.h" |  | 
|   18 #include "blimp/common/proto/blob_cache.pb.h" |  | 
|   19 #include "blimp/engine/renderer/blimp_engine_picture_cache.h" |  | 
|   20 #include "blimp/engine/renderer/blob_channel_sender_proxy.h" |  | 
|   21 #include "content/public/renderer/render_frame.h" |  | 
|   22 #include "third_party/libwebp/webp/encode.h" |  | 
|   23 #include "third_party/skia/include/core/SkData.h" |  | 
|   24 #include "third_party/skia/include/core/SkPicture.h" |  | 
|   25 #include "third_party/skia/include/core/SkPixelSerializer.h" |  | 
|   26 #include "third_party/skia/include/core/SkUnPreMultiply.h" |  | 
|   27  |  | 
|   28 namespace blimp { |  | 
|   29 namespace engine { |  | 
|   30 namespace { |  | 
|   31  |  | 
|   32 sk_sp<SkData> BlobCacheImageMetadataProtoAsSkData( |  | 
|   33     const BlobCacheImageMetadata& proto) { |  | 
|   34   int signed_size = proto.ByteSize(); |  | 
|   35   size_t unsigned_size = base::checked_cast<size_t>(signed_size); |  | 
|   36   std::vector<uint8_t> serialized(unsigned_size); |  | 
|   37   proto.SerializeWithCachedSizesToArray(serialized.data()); |  | 
|   38   return SkData::MakeWithCopy(serialized.data(), serialized.size()); |  | 
|   39 } |  | 
|   40  |  | 
|   41 // For each pixel, un-premultiplies the alpha-channel for each of the RGB |  | 
|   42 // channels. As an example, for a channel value that before multiplication was |  | 
|   43 // 255, and after applying an alpha of 128, the premultiplied pixel would be |  | 
|   44 // 128. The un-premultiply step uses the alpha-channel to get back to 255. The |  | 
|   45 // alpha channel is kept unchanged. |  | 
|   46 void UnPremultiply(const unsigned char* in_pixels, |  | 
|   47                    unsigned char* out_pixels, |  | 
|   48                    size_t pixel_count) { |  | 
|   49   const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); |  | 
|   50   for (; pixel_count-- > 0; in_pixels += 4) { |  | 
|   51     unsigned char alpha = in_pixels[3]; |  | 
|   52     if (alpha == 255) {  // Full opacity, just blindly copy. |  | 
|   53       *out_pixels++ = in_pixels[0]; |  | 
|   54       *out_pixels++ = in_pixels[1]; |  | 
|   55       *out_pixels++ = in_pixels[2]; |  | 
|   56       *out_pixels++ = alpha; |  | 
|   57     } else { |  | 
|   58       SkUnPreMultiply::Scale scale = table[alpha]; |  | 
|   59       *out_pixels++ = SkUnPreMultiply::ApplyScale(scale, in_pixels[0]); |  | 
|   60       *out_pixels++ = SkUnPreMultiply::ApplyScale(scale, in_pixels[1]); |  | 
|   61       *out_pixels++ = SkUnPreMultiply::ApplyScale(scale, in_pixels[2]); |  | 
|   62       *out_pixels++ = alpha; |  | 
|   63     } |  | 
|   64   } |  | 
|   65   } |  | 
|   66  |  | 
|   67   bool PlatformPictureImport(const unsigned char* pixels, |  | 
|   68                              WebPPicture* picture, |  | 
|   69                              SkAlphaType alphaType) { |  | 
|   70     // Each pixel uses 4 bytes (RGBA) which affects the stride per row. |  | 
|   71     int row_stride = picture->width * 4; |  | 
|   72     if (alphaType == kPremul_SkAlphaType) { |  | 
|   73       // Need to unpremultiply each pixel, each pixel using 4 bytes (RGBA). |  | 
|   74       size_t pixel_count = picture->height * picture->width; |  | 
|   75       std::vector<unsigned char> unpremul_pixels(pixel_count * 4); |  | 
|   76       UnPremultiply(pixels, unpremul_pixels.data(), pixel_count); |  | 
|   77       if (SK_B32_SHIFT)  // Android |  | 
|   78         return WebPPictureImportRGBA(picture, unpremul_pixels.data(), |  | 
|   79                                      row_stride); |  | 
|   80       return WebPPictureImportBGRA(picture, unpremul_pixels.data(), row_stride); |  | 
|   81     } |  | 
|   82  |  | 
|   83     if (SK_B32_SHIFT)  // Android |  | 
|   84       return WebPPictureImportRGBA(picture, pixels, row_stride); |  | 
|   85     return WebPPictureImportBGRA(picture, pixels, row_stride); |  | 
|   86   } |  | 
|   87  |  | 
|   88   }  // namespace |  | 
|   89  |  | 
|   90   EngineImageSerializationProcessor::EngineImageSerializationProcessor( |  | 
|   91       std::unique_ptr<BlobChannelSenderProxy> blob_channel) |  | 
|   92       : blob_channel_(std::move(blob_channel)) { |  | 
|   93     DCHECK(blob_channel_); |  | 
|   94     WebPMemoryWriterInit(&writer_state_); |  | 
|   95 } |  | 
|   96  |  | 
|   97 EngineImageSerializationProcessor::~EngineImageSerializationProcessor() { |  | 
|   98   WebPMemoryWriterClear(&writer_state_); |  | 
|   99 } |  | 
|  100  |  | 
|  101 std::unique_ptr<cc::EnginePictureCache> |  | 
|  102 EngineImageSerializationProcessor::CreateEnginePictureCache() { |  | 
|  103   return base::MakeUnique<BlimpEnginePictureCache>(this); |  | 
|  104 } |  | 
|  105  |  | 
|  106 std::unique_ptr<cc::ClientPictureCache> |  | 
|  107 EngineImageSerializationProcessor::CreateClientPictureCache() { |  | 
|  108   NOTREACHED(); |  | 
|  109   return nullptr; |  | 
|  110 } |  | 
|  111  |  | 
|  112 bool EngineImageSerializationProcessor::onUseEncodedData(const void* data, |  | 
|  113                                                          size_t len) { |  | 
|  114   TRACE_EVENT1("blimp", "WebPImageEncoded::UsingEncodedData", |  | 
|  115                "OriginalImageSize", len); |  | 
|  116   // Encode all images regardless of their format, including WebP images. |  | 
|  117   return false; |  | 
|  118 } |  | 
|  119  |  | 
|  120 SkData* EngineImageSerializationProcessor::onEncode(const SkPixmap& pixmap) { |  | 
|  121   TRACE_EVENT0("blimp", "WebImageEncoder::onEncode"); |  | 
|  122  |  | 
|  123   // Ensure width and height are valid dimensions. |  | 
|  124   DCHECK_GT(pixmap.width(), 0); |  | 
|  125   DCHECK_LE(pixmap.width(), WEBP_MAX_DIMENSION); |  | 
|  126   DCHECK_GT(pixmap.height(), 0); |  | 
|  127   DCHECK_LE(pixmap.height(), WEBP_MAX_DIMENSION); |  | 
|  128  |  | 
|  129   // Send the image to the client via the BlobChannel if we know that the |  | 
|  130   // client doesn't have it. |  | 
|  131   const BlobId blob_id = CalculateBlobId(pixmap.addr(), pixmap.getSafeSize()); |  | 
|  132   if (!blob_channel_->IsInEngineCache(blob_id)) { |  | 
|  133     blob_channel_->PutBlob(blob_id, EncodeImageAsBlob(pixmap)); |  | 
|  134     DCHECK(blob_channel_->IsInEngineCache(blob_id)); |  | 
|  135   } |  | 
|  136  |  | 
|  137   // Push the blob to the client, if the client doesn't already have it. |  | 
|  138   if (!blob_channel_->IsInClientCache(blob_id)) { |  | 
|  139     blob_channel_->DeliverBlob(blob_id); |  | 
|  140   } |  | 
|  141  |  | 
|  142   // Construct a proto with the image metadata. |  | 
|  143   BlobCacheImageMetadata proto; |  | 
|  144   proto.set_id(blob_id); |  | 
|  145   proto.set_width(pixmap.width()); |  | 
|  146   proto.set_height(pixmap.height()); |  | 
|  147  |  | 
|  148   sk_sp<SkData> sk_data = BlobCacheImageMetadataProtoAsSkData(proto); |  | 
|  149   DVLOG(3) << "Returning image ID " << BlobIdToString(blob_id); |  | 
|  150   return sk_data.release(); |  | 
|  151 } |  | 
|  152  |  | 
|  153 scoped_refptr<BlobData> EngineImageSerializationProcessor::EncodeImageAsBlob( |  | 
|  154     const SkPixmap& pixmap) { |  | 
|  155   DVLOG(2) << "Encoding image color_type=" << pixmap.colorType() |  | 
|  156            << ", alpha_type=" << pixmap.alphaType() << " " << pixmap.width() |  | 
|  157            << "x" << pixmap.height(); |  | 
|  158  |  | 
|  159   WebPConfig config; |  | 
|  160   CHECK(WebPConfigInit(&config)); |  | 
|  161  |  | 
|  162   WebPPicture picture; |  | 
|  163   CHECK(WebPPictureInit(&picture)); |  | 
|  164   picture.width = pixmap.width(); |  | 
|  165   picture.height = pixmap.height(); |  | 
|  166  |  | 
|  167   // Import picture from raw pixels. |  | 
|  168   auto* pixel_chars = static_cast<const unsigned char*>(pixmap.addr()); |  | 
|  169   CHECK(PlatformPictureImport(pixel_chars, &picture, pixmap.alphaType())); |  | 
|  170  |  | 
|  171   // Set up the writer parameters. |  | 
|  172   writer_state_.size = 0; |  | 
|  173   picture.custom_ptr = &writer_state_; |  | 
|  174   picture.writer = &WebPMemoryWrite; |  | 
|  175  |  | 
|  176   // Setup the configuration for the output WebP picture. This is currently |  | 
|  177   // the same as the default configuration for WebP, but since any change in |  | 
|  178   // the WebP defaults would invalidate all caches they are hard coded. |  | 
|  179   config.lossless = 0; |  | 
|  180   config.quality = 75.0;  // between 0 (smallest file) and 100 (biggest). |  | 
|  181  |  | 
|  182   // TODO(nyquist): Move image encoding to a different thread when |  | 
|  183   // asynchronous loading of images is possible. The encode work currently |  | 
|  184   // blocks the render thread so we are dropping the method down to 0. |  | 
|  185   // crbug.com/603643. |  | 
|  186   config.method = 0;  // quality/speed trade-off (0=fast, 6=slower-better). |  | 
|  187  |  | 
|  188   TRACE_EVENT_BEGIN0("blimp", "WebPImageEncoder::onEncode WebPEncode"); |  | 
|  189   // Encode the picture using the given configuration. |  | 
|  190   bool success = WebPEncode(&config, &picture); |  | 
|  191   TRACE_EVENT_END1("blimp", "WebPImageEncoder::onEncode WebPEncode", |  | 
|  192                    "EncodedImageSize", static_cast<int>(writer_state_.size)); |  | 
|  193  |  | 
|  194   // Release the memory allocated by WebPPictureImport*(). This does not |  | 
|  195   // free the memory used by the picture object itself. |  | 
|  196   WebPPictureFree(&picture); |  | 
|  197  |  | 
|  198   if (!success) { |  | 
|  199     LOG(FATAL) << "WebPPictureEncode() failed."; |  | 
|  200     return nullptr; |  | 
|  201   } |  | 
|  202  |  | 
|  203   scoped_refptr<BlobData> blob_data(new BlobData); |  | 
|  204   blob_data->data.assign(reinterpret_cast<const char*>(writer_state_.mem), |  | 
|  205                          writer_state_.size); |  | 
|  206   return blob_data; |  | 
|  207 } |  | 
|  208  |  | 
|  209 }  // namespace engine |  | 
|  210 }  // namespace blimp |  | 
| OLD | NEW |