fix clip hole of camera

Signed-off-by: caocan <1532643766@qq.com>
Change-Id: I652bc31791406b0ebab984771a41d61557181ce6
This commit is contained in:
caocan
2021-12-28 21:35:34 +08:00
parent 65058ce5b4
commit 3f220e7863
14 changed files with 187 additions and 89 deletions
@@ -107,6 +107,7 @@ class MockRenderContext : public RenderContext {
public:
void Repaint(const RefPtr<RenderNode>& node) override {};
void PaintChild(const RefPtr<RenderNode>& child, const Offset& offset) override {};
void Restore() override {};
};
RefPtr<RenderContext> RenderContext::Create()
@@ -51,7 +51,11 @@ const char REGION_POSITION_Y[] = "region_position_y";
const char REGION_WIDTH[] = "region_width";
const char REGION_HEIGHT[] = "region_height";
constexpr int32_t DEFAULT_WIDTH = 640;
#ifdef PRODUCT_RK
constexpr int32_t DEFAULT_HEIGHT = 480;
#else
constexpr int32_t DEFAULT_HEIGHT = 360;
#endif
constexpr int32_t SURFACE_STRIDE_ALIGNMENT_VAL = 8;
constexpr int32_t PREVIEW_SURFACE_WIDTH = 640;
constexpr int32_t PREVIEW_SURFACE_HEIGHT = 480;
@@ -231,6 +235,10 @@ sptr<Surface> CameraCallback::createSubWindowSurface()
return nullptr;
}
subwindow_->GetSurface()->SetQueueSize(QUEUE_SIZE);
hasMarkWhole_ = false;
subwindow_->OnBeforeFrameSubmit([this]() {
OnFirstBufferAvailable();
});
}
previewSurface_ = subwindow_->GetSurface();
previewSurface_->SetUserData(SURFACE_STRIDE_ALIGNMENT, std::to_string(SURFACE_STRIDE_ALIGNMENT_VAL));
@@ -245,10 +253,19 @@ sptr<Surface> CameraCallback::createSubWindowSurface()
previewSurface_->SetUserData(REGION_HEIGHT, std::to_string(windowSize_.Height()));
previewSurface_->SetUserData(REGION_POSITION_X, std::to_string(windowOffset_.GetX()));
previewSurface_->SetUserData(REGION_POSITION_Y, std::to_string(windowOffset_.GetY()));
MarkWhole();
return previewSurface_;
}
void CameraCallback::OnFirstBufferAvailable()
{
if (hasMarkWhole_) {
return;
}
LOGI("CameraCallback:OnFirstBufferAvailable first MarkWhole.");
MarkWhole();
hasMarkWhole_ = true;
}
void CameraCallback::MarkWhole()
{
auto context = context_.Upgrade();
@@ -262,14 +279,16 @@ void CameraCallback::MarkWhole()
if (renderNode) {
renderNode->SetHasSubWindow(true);
}
RenderNode::MarkWholeRender(renderNode_, true);
LOGI("CameraCallback:MarkWhole success.");
}
void CameraCallback::SetLayoutOffset(double x, double y)
{
layoutOffset_.SetX(x);
layoutOffset_.SetY(y);
if (subwindow_) {
LOGI("CameraCallback::SetLayoutOffset: move %{public}lf %{public}lf ", x, y);
if (hasMarkWhole_ && subwindow_) {
LOGI("CameraCallback:Hole change %{public}lf %{public}lf ", x, y);
MarkWhole();
}
}
@@ -397,8 +416,13 @@ int32_t CameraCallback::PrepareCamera(bool bIsRecorder)
surface = createSubWindowSurface();
LOGI("Preview surface width: %{public}d, height: %{public}d", surface->GetDefaultWidth(),
surface->GetDefaultHeight());
#ifdef PRODUCT_RK
previewOutput_ = camManagerObj->CreateCustomPreviewOutput(surface, PREVIEW_SURFACE_WIDTH,
PREVIEW_SURFACE_HEIGHT);
#else
previewOutput_ = camManagerObj->CreateCustomPreviewOutput(surface, surface->GetDefaultHeight(),
surface->GetDefaultWidth());
#endif
if (previewOutput_ == nullptr) {
LOGE("Failed to create PreviewOutput");
return -1;
@@ -90,6 +90,7 @@ public:
void OnCameraSizeChange(double width, double height);
void OnCameraOffsetChange(double x, double y);
void MarkWhole();
void OnFirstBufferAvailable();
void SetLayoutOffset(double x, double y);
void SetLayoutSize(double width, double height)
{
@@ -102,6 +103,8 @@ public:
}
friend class CaptureListener;
bool hasMarkWhole_ = false;
protected:
void CloseRecorder();
@@ -83,6 +83,7 @@ class MockRenderContext : public RenderContext {
public:
void Repaint(const RefPtr<RenderNode>& node) override {};
void PaintChild(const RefPtr<RenderNode>& child, const Offset& offset) override {};
void Restore() override {};
};
class MockRenderStack : public RenderStack {
@@ -135,6 +135,7 @@ class MockRenderContext : public RenderContext {
public:
void Repaint(const RefPtr<RenderNode>& node) override {};
void PaintChild(const RefPtr<RenderNode>& child, const Offset& offset) override {};
void Restore() override {};
};
class MockRenderImage : public RenderImage {
@@ -107,6 +107,7 @@ class MockRenderContext : public RenderContext {
public:
void Repaint(const RefPtr<RenderNode>& node) override {};
void PaintChild(const RefPtr<RenderNode>& child, const Offset& offset) override {};
void Restore() override {};
};
RefPtr<RenderContext> RenderContext::Create()
@@ -67,6 +67,14 @@ void FlutterRenderContext::PaintChild(const RefPtr<RenderNode>& child, const Off
if (name != "FlutterRenderForm") {
if (child->NeedRender()) {
FlutterRenderContext context;
auto pipelineContext = child->GetContext().Upgrade();
LOGI("Hole: child canvas render");
auto transparentHole = pipelineContext->GetTransparentHole();
if (transparentHole.IsValid() && child->GetNeedClip()) {
Offset childOffset = rect.GetOffset();
Rect hole = transparentHole - childOffset;
context.SetClipHole(hole);
}
context.Repaint(child);
} else {
// No need to repaint, notify to update AccessibilityNode info.
@@ -110,6 +118,12 @@ void FlutterRenderContext::StartRecording()
recorder_ = flutter::PictureRecorder::Create();
canvas_ = flutter::Canvas::Create(
recorder_.get(), estimatedRect_.Left(), estimatedRect_.Top(), estimatedRect_.Right(), estimatedRect_.Bottom());
if (clipHole_.IsValid()) {
canvas_->save();
needRestoreHole_ = true;
canvas_->clipRect(clipHole_.Left(), clipHole_.Top(),
clipHole_.Right(), clipHole_.Bottom(), SkClipOp::kDifference);
}
containerLayer_->AddChildren(currentLayer_);
}
@@ -119,6 +133,10 @@ void FlutterRenderContext::StopRecordingIfNeeded()
return;
}
if (needRestoreHole_) {
canvas_->restore();
needRestoreHole_ = false;
}
currentLayer_->SetPicture(recorder_->endRecording());
currentLayer_ = nullptr;
recorder_ = nullptr;
@@ -144,29 +162,6 @@ bool FlutterRenderContext::IsIntersectWith(const RefPtr<RenderNode>& child, Offs
return true;
}
void FlutterRenderContext::ClipHoleBegin(const Rect& holeRect)
{
auto canvas = GetCanvas();
if (!canvas) {
return;
}
LOGI("Hole: PrePaint save clip.");
canvas->save();
if (holeRect.IsValid()) {
canvas->clipRect(holeRect.Left(), holeRect.Top(), holeRect.Right(), holeRect.Bottom(), SkClipOp::kDifference);
}
}
void FlutterRenderContext::ClipHoleEnd()
{
LOGI("Hole: PostPaint restore clip");
auto canvas = GetCanvas();
if (!canvas) {
return;
}
canvas->restore();
}
void FlutterRenderContext::InitContext(RenderLayer layer, const Rect& rect)
{
LOGD("InitContext with width %{public}lf height %{public}lf", rect.Width(), rect.Height());
@@ -183,4 +178,12 @@ flutter::Canvas* FlutterRenderContext::GetCanvas()
return canvas_.get();
}
void FlutterRenderContext::Restore()
{
auto canvas = GetCanvas();
if (canvas != nullptr) {
canvas->restore();
}
}
} // namespace OHOS::Ace
@@ -39,8 +39,7 @@ public:
void Repaint(const RefPtr<RenderNode>& node) override;
void PaintChild(const RefPtr<RenderNode>& child, const Offset& offset) override;
bool IsIntersectWith(const RefPtr<RenderNode>& child, Offset& offset) override;
void ClipHoleBegin(const Rect& holeRect) override;
void ClipHoleEnd() override;
void Restore() override;
void InitContext(RenderLayer layer, const Rect& rect);
flutter::Canvas* GetCanvas();
+17 -2
View File
@@ -41,11 +41,26 @@ public:
virtual void Repaint(const RefPtr<RenderNode>&) = 0;
virtual void PaintChild(const RefPtr<RenderNode>&, const Offset& offset) = 0;
virtual bool IsIntersectWith(const RefPtr<RenderNode>& child, Offset& offset) { return true; }
virtual void ClipHoleBegin(const Rect& holeRect) {}
virtual void ClipHoleEnd() {}
virtual void Restore() = 0;
virtual void SetClipHole(Rect clipHole)
{
clipHole_ = clipHole;
}
void SetNeedRestoreHole(bool restore)
{
needRestoreHole_ = restore;
}
bool GetNeedRestoreHole() const
{
return needRestoreHole_;
}
protected:
RenderContext() = default;
Rect clipHole_;
bool needRestoreHole_ = false;
};
} // namespace OHOS::Ace
+61 -31
View File
@@ -17,6 +17,8 @@
#include <algorithm>
#include <set>
#include <sstream>
#include <unistd.h>
#ifdef ENABLE_ROSEN_BACKEND
#include "render_service_client/core/ui/rs_node.h"
@@ -65,6 +67,51 @@ constexpr Dimension FOCUS_BOUNDARY = 4.0_vp; // focus padding + effect boundary,
RenderNode::RenderNode(bool takeBoundary) : takeBoundary_(takeBoundary) {}
void RenderNode::MarkTreeRender(const RefPtr<RenderNode>& root, bool& meetHole, bool needFlush)
{
if (root->GetHasSubWindow()) {
meetHole = true;
}
if (meetHole) {
root->SetNeedClip(false);
LOGD("Hole: has meet hole, no need clip");
} else {
root->SetNeedClip(true);
LOGD("Hole: has not meet hole, need clip");
}
if (needFlush) {
root->MarkNeedRender();
}
LOGI("Hole: MarkTreeRender %{public}s", AceType::TypeName(Referenced::RawPtr(root)));
bool subMeetHole = meetHole;
for (auto child: root->GetChildren()) {
MarkTreeRender(child, subMeetHole, needFlush);
}
meetHole = subMeetHole;
}
void RenderNode::MarkWholeRender(const WeakPtr<RenderNode>& nodeWeak, bool needFlush)
{
auto node = nodeWeak.Upgrade();
if (!node) {
LOGE("Hole: MarkWholeRender node is null");
return;
}
auto parentWeak = node->GetParent();
auto parent = parentWeak.Upgrade();
while (parent) {
node = parent;
parentWeak = node->GetParent();
parent = parentWeak.Upgrade();
}
bool meetHole = false;
MarkTreeRender(node, meetHole, needFlush);
}
void RenderNode::AddChild(const RefPtr<RenderNode>& child, int32_t slot)
{
if (!child) {
@@ -82,6 +129,10 @@ void RenderNode::AddChild(const RefPtr<RenderNode>& child, int32_t slot)
std::advance(pos, slot);
children_.insert(pos, child);
child->SetParent(AceType::WeakClaim(this));
auto context = context_.Upgrade();
if (context && context->GetTransparentHole().IsValid()) {
MarkWholeRender(AceType::WeakClaim(this), true);
}
child->SetDepth(GetDepth() + 1);
OnChildAdded(child);
disappearingNodes_.remove(child);
@@ -316,7 +367,16 @@ void RenderNode::RenderWithContext(RenderContext& context, const Offset& offset)
onLayoutReady_(std::string("\"layoutReady\",null,null"));
}
pendingDispatchLayoutReady_ = false;
ClipHole(context, offset);
if (GetHasSubWindow() || !GetNeedClip()) {
LOGI("Hole: meet subwindow node or no need clip");
if (context.GetNeedRestoreHole()) {
context.Restore();
context.SetNeedRestoreHole(false);
context.SetClipHole(Rect());
}
} else {
context.SetClipHole(context_.Upgrade()->GetTransparentHole());
}
Paint(context, offset);
for (const auto& item : SortChildrenByZIndex(disappearingNodes_)) {
PaintChild(item, context, offset);
@@ -367,36 +427,6 @@ void RenderNode::PaintChild(const RefPtr<RenderNode>& child, RenderContext& cont
}
}
void RenderNode::ClipHole(RenderContext& context, const Offset& offset)
{
LOGD("Hole: PrePaint RenderNode");
auto pipelineContext = GetContext().Upgrade();
if (pipelineContext && pipelineContext->GetIsHoleValid()) {
if (!(pipelineContext->GetHasClipHole())) {
if (!(pipelineContext->GetHasMeetSubWindowNode())) {
context.ClipHoleBegin(pipelineContext->GetTransparentHole());
pipelineContext->SetHasClipHole(true);
} else {
LOGI("Hole: hole status is wrong.");
}
} else {
if (!(pipelineContext->GetHasMeetSubWindowNode())) {
if (GetHasSubWindow()) {
context.ClipHoleEnd();
pipelineContext->SetHasMeetSubWindowNode(true);
} else {
LOGI("Hole: RenderNode has not SubWindow.");
}
} else {
LOGI("Hole: now clip has done.");
}
}
} else {
LOGD("Hole: hole is not valid.");
}
}
void RenderNode::MarkNeedLayout(bool selfOnly, bool forceParent)
{
bool addSelf = false;
+15 -2
View File
@@ -68,6 +68,10 @@ public:
using SlipFactorSetting = std::function<void(double)>;
~RenderNode() override = default;
static void MarkTreeRender(const RefPtr<RenderNode>& root, bool& meetHole, bool needFlush);
static void MarkWholeRender(const WeakPtr<RenderNode>& nodeWeak, bool needFlush);
void SetZIndex(int32_t zIndex)
{
zIndex_ = zIndex;
@@ -964,8 +968,6 @@ public:
bool IsPaintOutOfParent();
void UpdatePosition();
virtual void ClipHole(RenderContext& context, const Offset& offset);
void SetHasSubWindow(bool hasSubWindow)
{
hasSubWindow_ = hasSubWindow;
@@ -1004,6 +1006,16 @@ public:
inspector_ = inspectorNode;
}
virtual void SetNeedClip(bool needClip)
{
needClip_ = needClip;
}
bool GetNeedClip()
{
return needClip_;
}
protected:
explicit RenderNode(bool takeBoundary = false);
virtual void ClearRenderObject();
@@ -1090,6 +1102,7 @@ protected:
void MarkNeedSyncGeometryProperties();
bool hasSubWindow_ = false;
bool needClip_ = false;
WeakPtr<PipelineContext> context_;
Size viewPort_;
Point globalPoint_;
@@ -69,6 +69,14 @@ void RosenRenderContext::PaintChild(const RefPtr<RenderNode>& child, const Offse
rsNode_->AddChild(childRSNode, -1);
if (child->NeedRender()) {
RosenRenderContext context;
auto pipelineContext = child->GetContext().Upgrade();
LOGI("Hole: child canvas render");
auto transparentHole = pipelineContext->GetTransparentHole();
if (transparentHole.IsValid() && child->GetNeedClip()) {
Offset childOffset = rect.GetOffset();
Rect hole = transparentHole - childOffset;
context.SetClipHole(hole);
}
context.Repaint(child);
} else {
// No need to repaint, notify to update AccessibilityNode info.
@@ -84,6 +92,12 @@ void RosenRenderContext::StartRecording()
recorder_ = new SkPictureRecorder();
recordingCanvas_ = recorder_->beginRecording(
SkRect::MakeXYWH(estimatedRect_.Left(), estimatedRect_.Top(), estimatedRect_.Width(), estimatedRect_.Height()));
if (clipHole_.IsValid()) {
recordingCanvas_->save();
needRestoreHole_ = true;
recordingCanvas_->clipRect(clipHole_.Left(), clipHole_.Top(),
clipHole_.Right(), clipHole_.Bottom(), SkClipOp::kDifference);
}
}
void RosenRenderContext::StopRecordingIfNeeded()
@@ -92,6 +106,11 @@ void RosenRenderContext::StopRecordingIfNeeded()
return;
}
if (needRestoreHole_) {
recordingCanvas_->restore();
needRestoreHole_ = false;
}
delete recorder_;
recorder_ = nullptr;
recordingCanvas_ = nullptr;
@@ -116,30 +135,6 @@ bool RosenRenderContext::IsIntersectWith(const RefPtr<RenderNode>& child, Offset
return true;
}
void RosenRenderContext::ClipHoleBegin(const Rect& holeRect)
{
auto canvas = GetCanvas();
if (!canvas) {
return;
}
LOGI("Hole: PrePaint save clip.");
canvas->save();
if (holeRect.IsValid()) {
canvas->clipRect(
{ holeRect.Left(), holeRect.Top(), holeRect.Right(), holeRect.Bottom() }, SkClipOp::kDifference);
}
}
void RosenRenderContext::ClipHoleEnd()
{
LOGI("Hole: PostPaint restore clip");
auto canvas = GetCanvas();
if (!canvas) {
return;
}
canvas->restore();
}
void RosenRenderContext::InitContext(
const std::shared_ptr<RSNode>& rsNode, const Rect& rect, const Offset& initialOffset)
{
@@ -188,4 +183,13 @@ sk_sp<SkImage> RosenRenderContext::FinishRecordingAsImage()
nullptr, SkImage::BitDepth::kU8, nullptr);
return image;
}
void RosenRenderContext::Restore()
{
auto canvas = GetCanvas();
if (canvas != nullptr) {
canvas->restore();
}
}
} // namespace OHOS::Ace
@@ -39,8 +39,7 @@ public:
void Repaint(const RefPtr<RenderNode>& node) override;
void PaintChild(const RefPtr<RenderNode>& child, const Offset& offset) override;
bool IsIntersectWith(const RefPtr<RenderNode>& child, Offset& offset) override;
void ClipHoleBegin(const Rect& holeRect) override;
void ClipHoleEnd() override;
void Restore() override;
void InitContext(
const std::shared_ptr<RSNode>& rsNode, const Rect& rect, const Offset& initialOffset = Offset::Zero());
@@ -538,6 +538,10 @@ void PipelineContext::FlushRender()
UpdateNodesNeedDrawOnPixelMap();
auto context = RenderContext::Create();
if (transparentHole_.IsValid()) {
LOGD("Hole: set transparentHole_ in FlushRender");
context->SetClipHole(transparentHole_);
}
if (!dirtyRenderNodes_.empty()) {
decltype(dirtyRenderNodes_) dirtyNodes(std::move(dirtyRenderNodes_));
for (const auto& dirtyNode : dirtyNodes) {