blob: 2e87510cc08853c098e029264a2a442fb9c5f3e4 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "flutter/shell/platform/darwin/ios/ios_surface_software.h"
#include <QuartzCore/CALayer.h>
#include <memory>
#include "flutter/fml/logging.h"
#include "flutter/fml/platform/darwin/cf_utils.h"
#include "flutter/fml/trace_event.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/utils/mac/SkCGUtils.h"
namespace flutter {
IOSSurfaceSoftware::IOSSurfaceSoftware(const fml::scoped_nsobject<CALayer>& layer,
std::shared_ptr<IOSContext> context)
: IOSSurface(std::move(context)), layer_(layer) {}
IOSSurfaceSoftware::~IOSSurfaceSoftware() = default;
bool IOSSurfaceSoftware::IsValid() const {
return layer_;
}
void IOSSurfaceSoftware::UpdateStorageSizeIfNecessary() {
// Nothing to do here. We don't need an external entity to tell us when our
// backing store needs to be updated. Instead, we let the frame tell us its
// size so we can update to match. This method was added to work around
// Android oddities.
}
std::unique_ptr<Surface> IOSSurfaceSoftware::CreateGPUSurface(GrDirectContext* gr_context) {
if (!IsValid()) {
return nullptr;
}
auto surface = std::make_unique<GPUSurfaceSoftware>(this, true /* render to surface */);
if (!surface->IsValid()) {
return nullptr;
}
return surface;
}
sk_sp<SkSurface> IOSSurfaceSoftware::AcquireBackingStore(const SkISize& size) {
TRACE_EVENT0("flutter", "IOSSurfaceSoftware::AcquireBackingStore");
if (!IsValid()) {
return nullptr;
}
if (sk_surface_ != nullptr &&
SkISize::Make(sk_surface_->width(), sk_surface_->height()) == size) {
// The old and new surface sizes are the same. Nothing to do here.
return sk_surface_;
}
SkImageInfo info = SkImageInfo::MakeN32(size.fWidth, size.fHeight, kPremul_SkAlphaType,
SkColorSpace::MakeSRGB());
sk_surface_ = SkSurface::MakeRaster(info, nullptr);
return sk_surface_;
}
bool IOSSurfaceSoftware::PresentBackingStore(sk_sp<SkSurface> backing_store) {
TRACE_EVENT0("flutter", "IOSSurfaceSoftware::PresentBackingStore");
if (!IsValid() || backing_store == nullptr) {
return false;
}
SkPixmap pixmap;
if (!backing_store->peekPixels(&pixmap)) {
return false;
}
// Some basic sanity checking.
uint64_t expected_pixmap_data_size = pixmap.width() * pixmap.height() * 4;
const size_t pixmap_size = pixmap.computeByteSize();
if (expected_pixmap_data_size != pixmap_size) {
return false;
}
fml::CFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB());
// Setup the data provider that gives CG a view into the pixmap.
fml::CFRef<CGDataProviderRef> pixmap_data_provider(CGDataProviderCreateWithData(
nullptr, // info
pixmap.addr32(), // data
pixmap_size, // size
nullptr // release callback
));
if (!pixmap_data_provider) {
return false;
}
// Create the CGImageRef representation on the pixmap.
fml::CFRef<CGImageRef> pixmap_image(CGImageCreate(pixmap.width(), // width
pixmap.height(), // height
8, // bits per component
32, // bits per pixel
pixmap.rowBytes(), // bytes per row
colorspace, // colorspace
kCGImageAlphaPremultipliedLast, // bitmap info
pixmap_data_provider, // data provider
nullptr, // decode array
false, // should interpolate
kCGRenderingIntentDefault // rendering intent
));
if (!pixmap_image) {
return false;
}
layer_.get().contents = reinterpret_cast<id>(static_cast<CGImageRef>(pixmap_image));
return true;
}
} // namespace flutter