blob: 02e1d7b27ce60704030e3d75c024235ed86e8007 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/inspector/inspector_audits_agent.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_image.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/renderer/core/inspector/inspector_network_agent.h"
#include "third_party/blink/renderer/platform/graphics/image_data_buffer.h"
#include "third_party/blink/renderer/platform/wtf/text/base64.h"
namespace blink {
using protocol::Maybe;
using protocol::Response;
namespace encoding_enum = protocol::Audits::GetEncodedResponse::EncodingEnum;
namespace {
static constexpr int kMaximumEncodeImageWidthInPixels = 10000;
static constexpr int kMaximumEncodeImageHeightInPixels = 10000;
static constexpr double kDefaultEncodeQuality = 1;
bool EncodeAsImage(char* body,
size_t size,
const String& encoding,
const double quality,
Vector<unsigned char>* output) {
const WebSize maximum_size = WebSize(kMaximumEncodeImageWidthInPixels,
kMaximumEncodeImageHeightInPixels);
SkBitmap bitmap = WebImage::FromData(WebData(body, size), maximum_size);
if (bitmap.isNull())
return false;
SkImageInfo info =
SkImageInfo::Make(bitmap.width(), bitmap.height(), kRGBA_8888_SkColorType,
kUnpremul_SkAlphaType);
uint32_t row_bytes = static_cast<uint32_t>(info.minRowBytes());
Vector<unsigned char> pixel_storage(
SafeCast<wtf_size_t>(info.computeByteSize(row_bytes)));
SkPixmap pixmap(info, pixel_storage.data(), row_bytes);
sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
if (!image || !image->readPixels(pixmap, 0, 0))
return false;
std::unique_ptr<ImageDataBuffer> image_to_encode =
ImageDataBuffer::Create(pixmap);
if (!image_to_encode)
return false;
String mime_type_name = StringView("image/") + encoding;
ImageEncodingMimeType mime_type;
bool valid_mime_type = ParseImageEncodingMimeType(mime_type_name, mime_type);
DCHECK(valid_mime_type);
return image_to_encode->EncodeImage(mime_type, quality, output);
}
} // namespace
void InspectorAuditsAgent::Trace(blink::Visitor* visitor) {
visitor->Trace(network_agent_);
InspectorBaseAgent::Trace(visitor);
}
InspectorAuditsAgent::InspectorAuditsAgent(InspectorNetworkAgent* network_agent)
: network_agent_(network_agent) {}
InspectorAuditsAgent::~InspectorAuditsAgent() = default;
protocol::Response InspectorAuditsAgent::getEncodedResponse(
const String& request_id,
const String& encoding,
Maybe<double> quality,
Maybe<bool> size_only,
Maybe<protocol::Binary>* out_body,
int* out_original_size,
int* out_encoded_size) {
DCHECK(encoding == encoding_enum::Jpeg || encoding == encoding_enum::Png ||
encoding == encoding_enum::Webp);
String body;
bool is_base64_encoded;
Response response =
network_agent_->GetResponseBody(request_id, &body, &is_base64_encoded);
if (!response.isSuccess())
return response;
Vector<char> base64_decoded_buffer;
if (!is_base64_encoded || !Base64Decode(body, base64_decoded_buffer) ||
base64_decoded_buffer.size() == 0) {
return Response::Error("Failed to decode original image");
}
Vector<unsigned char> encoded_image;
if (!EncodeAsImage(base64_decoded_buffer.data(), base64_decoded_buffer.size(),
encoding, quality.fromMaybe(kDefaultEncodeQuality),
&encoded_image)) {
return Response::Error("Could not encode image with given settings");
}
*out_original_size = static_cast<int>(base64_decoded_buffer.size());
*out_encoded_size = static_cast<int>(encoded_image.size());
if (!size_only.fromMaybe(false)) {
*out_body = protocol::Binary::fromVector(std::move(encoded_image));
}
return Response::OK();
}
} // namespace blink