Commit 49441e8e authored by Vladimir Levin's avatar Vladimir Levin Committed by Commit Bot

Combine BoxCliper{,Base} and NGBoxClipper into a single ScopedBoxClipper.

This patch combines three classes into one with two constructors. This is
in preparation for using ContentsProperties instead of a specific contents properties'
clip. There are situations where we do want only the clip and only if the
contents properties' clip is different from local border box properties clip,
so that's left for a follow-up patch.

Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng;luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I2ed2f0c45918c8f1d79db054ef975234e46821ea
Reviewed-on: https://chromium-review.googlesource.com/1171674Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Commit-Queue: vmpstr <vmpstr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585175}
parent 98a5bafd
...@@ -21,10 +21,6 @@ blink_core_sources("paint") { ...@@ -21,10 +21,6 @@ blink_core_sources("paint") {
"block_painter.h", "block_painter.h",
"box_border_painter.cc", "box_border_painter.cc",
"box_border_painter.h", "box_border_painter.h",
"box_clipper.cc",
"box_clipper.h",
"box_clipper_base.cc",
"box_clipper_base.h",
"box_decoration_data.cc", "box_decoration_data.cc",
"box_decoration_data.h", "box_decoration_data.h",
"box_model_object_painter.cc", "box_model_object_painter.cc",
...@@ -124,8 +120,6 @@ blink_core_sources("paint") { ...@@ -124,8 +120,6 @@ blink_core_sources("paint") {
"multi_column_set_painter.h", "multi_column_set_painter.h",
"ng/ng_block_flow_painter.cc", "ng/ng_block_flow_painter.cc",
"ng/ng_block_flow_painter.h", "ng/ng_block_flow_painter.h",
"ng/ng_box_clipper.cc",
"ng/ng_box_clipper.h",
"ng/ng_box_fragment_painter.cc", "ng/ng_box_fragment_painter.cc",
"ng/ng_box_fragment_painter.h", "ng/ng_box_fragment_painter.h",
"ng/ng_fragment_painter.cc", "ng/ng_fragment_painter.cc",
...@@ -190,6 +184,8 @@ blink_core_sources("paint") { ...@@ -190,6 +184,8 @@ blink_core_sources("paint") {
"root_inline_box_painter.h", "root_inline_box_painter.h",
"rounded_inner_rect_clipper.cc", "rounded_inner_rect_clipper.cc",
"rounded_inner_rect_clipper.h", "rounded_inner_rect_clipper.h",
"scoped_box_clipper.cc",
"scoped_box_clipper.h",
"scrollable_area_painter.cc", "scrollable_area_painter.cc",
"scrollable_area_painter.h", "scrollable_area_painter.h",
"scrollbar_painter.cc", "scrollbar_painter.cc",
......
...@@ -13,12 +13,12 @@ ...@@ -13,12 +13,12 @@
#include "third_party/blink/renderer/core/layout/layout_inline.h" #include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/block_flow_painter.h" #include "third_party/blink/renderer/core/paint/block_flow_painter.h"
#include "third_party/blink/renderer/core/paint/box_clipper.h"
#include "third_party/blink/renderer/core/paint/box_painter.h" #include "third_party/blink/renderer/core/paint/box_painter.h"
#include "third_party/blink/renderer/core/paint/object_painter.h" #include "third_party/blink/renderer/core/paint/object_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h" #include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h" #include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/scoped_box_clipper.h"
#include "third_party/blink/renderer/core/paint/scrollable_area_painter.h" #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h" #include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h" #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
...@@ -54,7 +54,9 @@ void BlockPainter::Paint(const PaintInfo& paint_info) { ...@@ -54,7 +54,9 @@ void BlockPainter::Paint(const PaintInfo& paint_info) {
if (original_phase != PaintPhase::kSelfBlockBackgroundOnly && if (original_phase != PaintPhase::kSelfBlockBackgroundOnly &&
original_phase != PaintPhase::kSelfOutlineOnly) { original_phase != PaintPhase::kSelfOutlineOnly) {
BoxClipper clipper(layout_block_, local_paint_info); base::Optional<ScopedBoxClipper> box_clipper;
if (local_paint_info.phase != PaintPhase::kMask)
box_clipper.emplace(layout_block_, local_paint_info);
layout_block_.PaintObject(local_paint_info, paint_offset); layout_block_.PaintObject(local_paint_info, paint_offset);
} }
......
// Copyright 2014 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/paint/box_clipper.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
DISABLE_CFI_PERF
BoxClipper::BoxClipper(const LayoutBox& box, const PaintInfo& paint_info)
: box_(box), paint_info_(paint_info) {
DCHECK(paint_info_.phase != PaintPhase::kSelfBlockBackgroundOnly &&
paint_info_.phase != PaintPhase::kSelfOutlineOnly);
if (paint_info_.phase == PaintPhase::kMask)
return;
InitializeScopedClipProperty(paint_info.FragmentToPaint(box_), box,
paint_info);
}
} // namespace blink
// Copyright 2014 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.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_BOX_CLIPPER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_BOX_CLIPPER_H_
#include "third_party/blink/renderer/core/paint/box_clipper_base.h"
#include "third_party/blink/renderer/platform/geometry/layout_point.h"
#include "third_party/blink/renderer/platform/graphics/paint/display_item.h"
namespace blink {
class LayoutBox;
class BoxClipper : public BoxClipperBase {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
public:
BoxClipper(const LayoutBox&, const PaintInfo&);
private:
const LayoutBox& box_;
const PaintInfo& paint_info_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_BOX_CLIPPER_H_
// 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/paint/box_clipper_base.h"
#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
DISABLE_CFI_PERF
void BoxClipperBase::InitializeScopedClipProperty(
const FragmentData* fragment,
const DisplayItemClient& client,
const PaintInfo& paint_info) {
if (!fragment)
return;
const auto* properties = fragment->PaintProperties();
if (!properties)
return;
const auto* clip = properties->OverflowClip()
? properties->OverflowClip()
: properties->InnerBorderRadiusClip();
if (!clip)
return;
scoped_clip_property_.emplace(paint_info.context.GetPaintController(), clip,
client,
paint_info.DisplayItemTypeForClipping());
}
} // namespace blink
// 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.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_BOX_CLIPPER_BASE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_BOX_CLIPPER_BASE_H_
#include "base/optional.h"
#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
namespace blink {
class DisplayItemClient;
class FragmentData;
struct PaintInfo;
class BoxClipperBase {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
protected:
void InitializeScopedClipProperty(const FragmentData*,
const DisplayItemClient&,
const PaintInfo&);
base::Optional<ScopedPaintChunkProperties> scoped_clip_property_;
};
} // namespace blink
#endif // BoxClipper_h
// 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/paint/ng/ng_box_clipper.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
NGBoxClipper::NGBoxClipper(const NGPaintFragment& fragment,
const PaintInfo& paint_info) {
DCHECK(paint_info.phase != PaintPhase::kSelfBlockBackgroundOnly &&
paint_info.phase != PaintPhase::kSelfOutlineOnly);
if (paint_info.phase == PaintPhase::kMask)
return;
DCHECK(fragment.GetLayoutObject());
InitializeScopedClipProperty(
paint_info.FragmentToPaint(*fragment.GetLayoutObject()), fragment,
paint_info);
}
} // namespace blink
// 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.
#ifndef NGBoxClipper_h
#define NGBoxClipper_h
#include "third_party/blink/renderer/core/paint/box_clipper_base.h"
namespace blink {
class NGPaintFragment;
class NGBoxClipper : public BoxClipperBase {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
public:
NGBoxClipper(const NGPaintFragment&, const PaintInfo&);
};
} // namespace blink
#endif // NGBoxClipper_h
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "third_party/blink/renderer/core/paint/background_image_geometry.h" #include "third_party/blink/renderer/core/paint/background_image_geometry.h"
#include "third_party/blink/renderer/core/paint/box_decoration_data.h" #include "third_party/blink/renderer/core/paint/box_decoration_data.h"
#include "third_party/blink/renderer/core/paint/list_marker_painter.h" #include "third_party/blink/renderer/core/paint/list_marker_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_box_clipper.h"
#include "third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h" #include "third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h" #include "third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h" #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
...@@ -30,6 +29,7 @@ ...@@ -30,6 +29,7 @@
#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h" #include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_phase.h" #include "third_party/blink/renderer/core/paint/paint_phase.h"
#include "third_party/blink/renderer/core/paint/scoped_box_clipper.h"
#include "third_party/blink/renderer/core/paint/scrollable_area_painter.h" #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect_outsets.h" #include "third_party/blink/renderer/platform/geometry/layout_rect_outsets.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h" #include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h"
...@@ -152,11 +152,12 @@ void NGBoxFragmentPainter::Paint(const PaintInfo& paint_info) { ...@@ -152,11 +152,12 @@ void NGBoxFragmentPainter::Paint(const PaintInfo& paint_info) {
if (original_phase != PaintPhase::kSelfBlockBackgroundOnly && if (original_phase != PaintPhase::kSelfBlockBackgroundOnly &&
original_phase != PaintPhase::kSelfOutlineOnly) { original_phase != PaintPhase::kSelfOutlineOnly) {
base::Optional<NGBoxClipper> box_clipper; base::Optional<ScopedBoxClipper> box_clipper;
if (original_phase == PaintPhase::kForeground || if (original_phase == PaintPhase::kForeground ||
original_phase == PaintPhase::kFloat || original_phase == PaintPhase::kFloat ||
original_phase == PaintPhase::kDescendantOutlinesOnly) original_phase == PaintPhase::kDescendantOutlinesOnly) {
box_clipper.emplace(box_fragment_, info); box_clipper.emplace(box_fragment_, info);
}
PaintObject(info, paint_offset); PaintObject(info, paint_offset);
} }
...@@ -545,7 +546,7 @@ void NGBoxFragmentPainter::PaintAllPhasesAtomically( ...@@ -545,7 +546,7 @@ void NGBoxFragmentPainter::PaintAllPhasesAtomically(
local_paint_info.phase = PaintPhase::kFloat; local_paint_info.phase = PaintPhase::kFloat;
PaintObject(local_paint_info, paint_offset); PaintObject(local_paint_info, paint_offset);
{ {
NGBoxClipper box_clipper(box_fragment_, local_paint_info); ScopedBoxClipper box_clipper(box_fragment_, local_paint_info);
local_paint_info.phase = PaintPhase::kForeground; local_paint_info.phase = PaintPhase::kForeground;
PaintObject(local_paint_info, paint_offset); PaintObject(local_paint_info, paint_offset);
} }
......
// Copyright 2014 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/paint/scoped_box_clipper.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
namespace blink {
DISABLE_CFI_PERF
ScopedBoxClipper::ScopedBoxClipper(const LayoutBox& box,
const PaintInfo& paint_info) {
InitializeScopedProperties(paint_info.FragmentToPaint(box), box, paint_info);
}
DISABLE_CFI_PERF
ScopedBoxClipper::ScopedBoxClipper(const NGPaintFragment& fragment,
const PaintInfo& paint_info) {
DCHECK(fragment.GetLayoutObject());
InitializeScopedProperties(
paint_info.FragmentToPaint(*fragment.GetLayoutObject()), fragment,
paint_info);
}
void ScopedBoxClipper::InitializeScopedProperties(
const FragmentData* fragment_data,
const DisplayItemClient& client,
const PaintInfo& paint_info) {
DCHECK(paint_info.phase != PaintPhase::kSelfBlockBackgroundOnly &&
paint_info.phase != PaintPhase::kSelfOutlineOnly &&
paint_info.phase != PaintPhase::kMask);
if (!fragment_data)
return;
const auto* properties = fragment_data->PaintProperties();
if (!properties)
return;
const auto* clip = properties->OverflowClip()
? properties->OverflowClip()
: properties->InnerBorderRadiusClip();
if (!clip)
return;
scoped_properties_.emplace(paint_info.context.GetPaintController(), clip,
client, paint_info.DisplayItemTypeForClipping());
}
} // namespace blink
// Copyright 2014 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.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_SCOPED_BOX_CLIPPER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_SCOPED_BOX_CLIPPER_H_
#include "base/optional.h"
#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
namespace blink {
class DisplayItemClient;
class FragmentData;
class LayoutBox;
class NGPaintFragment;
struct PaintInfo;
// Within the scope of this object:
// - OverflowClip is applied if it exists
// - If it doesn't exist, then InnerBorderRadiusClip is applied if it exists.
// - If it doesn't exist, then properties are not modified.
// TODO(vmpstr): It should be possible to make this apply ContentsProperties
// instead of a contents clip only. However, there are situation where the
// LocalBorderBoxProperties().Clip(), which would be the fallback if neither
// OverflowClip nor InnerBorderRadiusClip exist, is not the correct clip to
// apply. We need to audit the usage to figure in which situations we want
// BoxClipper and in which situations we want OverflowClip or
// InnerBorderRadiusClip only.
class ScopedBoxClipper {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
public:
ScopedBoxClipper(const LayoutBox&, const PaintInfo&);
ScopedBoxClipper(const NGPaintFragment&, const PaintInfo&);
private:
void InitializeScopedProperties(const FragmentData*,
const DisplayItemClient&,
const PaintInfo&);
base::Optional<ScopedPaintChunkProperties> scoped_properties_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_SCOPED_BOX_BOX_CLIPPER_H_
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/core/layout/collapsed_border_value.h" #include "third_party/blink/renderer/core/layout/collapsed_border_value.h"
#include "third_party/blink/renderer/core/layout/layout_table.h" #include "third_party/blink/renderer/core/layout/layout_table.h"
#include "third_party/blink/renderer/core/layout/layout_table_section.h" #include "third_party/blink/renderer/core/layout/layout_table_section.h"
#include "third_party/blink/renderer/core/paint/box_clipper.h"
#include "third_party/blink/renderer/core/paint/box_painter.h" #include "third_party/blink/renderer/core/paint/box_painter.h"
#include "third_party/blink/renderer/core/paint/object_painter.h" #include "third_party/blink/renderer/core/paint/object_painter.h"
#include "third_party/blink/renderer/core/paint/paint_info.h" #include "third_party/blink/renderer/core/paint/paint_info.h"
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include "third_party/blink/renderer/core/layout/layout_table_cell.h" #include "third_party/blink/renderer/core/layout/layout_table_cell.h"
#include "third_party/blink/renderer/core/layout/layout_table_col.h" #include "third_party/blink/renderer/core/layout/layout_table_col.h"
#include "third_party/blink/renderer/core/layout/layout_table_row.h" #include "third_party/blink/renderer/core/layout/layout_table_row.h"
#include "third_party/blink/renderer/core/paint/box_clipper.h"
#include "third_party/blink/renderer/core/paint/box_painter.h" #include "third_party/blink/renderer/core/paint/box_painter.h"
#include "third_party/blink/renderer/core/paint/box_painter_base.h" #include "third_party/blink/renderer/core/paint/box_painter_base.h"
#include "third_party/blink/renderer/core/paint/collapsed_border_painter.h" #include "third_party/blink/renderer/core/paint/collapsed_border_painter.h"
...@@ -16,6 +15,7 @@ ...@@ -16,6 +15,7 @@
#include "third_party/blink/renderer/core/paint/paint_info.h" #include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_info_with_offset.h" #include "third_party/blink/renderer/core/paint/paint_info_with_offset.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/scoped_box_clipper.h"
#include "third_party/blink/renderer/core/paint/table_cell_painter.h" #include "third_party/blink/renderer/core/paint/table_cell_painter.h"
#include "third_party/blink/renderer/core/paint/table_row_painter.h" #include "third_party/blink/renderer/core/paint/table_row_painter.h"
#include "third_party/blink/renderer/platform/graphics/paint/display_item_cache_skipper.h" #include "third_party/blink/renderer/platform/graphics/paint/display_item_cache_skipper.h"
...@@ -70,9 +70,11 @@ void TableSectionPainter::PaintSection(const PaintInfo& paint_info) { ...@@ -70,9 +70,11 @@ void TableSectionPainter::PaintSection(const PaintInfo& paint_info) {
auto paint_offset = paint_info_with_offset.PaintOffset(); auto paint_offset = paint_info_with_offset.PaintOffset();
if (local_paint_info.phase != PaintPhase::kSelfOutlineOnly) { if (local_paint_info.phase != PaintPhase::kSelfOutlineOnly) {
base::Optional<BoxClipper> box_clipper; base::Optional<ScopedBoxClipper> box_clipper;
if (local_paint_info.phase != PaintPhase::kSelfBlockBackgroundOnly) if (local_paint_info.phase != PaintPhase::kSelfBlockBackgroundOnly &&
local_paint_info.phase != PaintPhase::kMask) {
box_clipper.emplace(layout_table_section_, local_paint_info); box_clipper.emplace(layout_table_section_, local_paint_info);
}
PaintObject(local_paint_info, paint_offset); PaintObject(local_paint_info, paint_offset);
} }
...@@ -128,7 +130,9 @@ void TableSectionPainter::PaintCollapsedSectionBorders( ...@@ -128,7 +130,9 @@ void TableSectionPainter::PaintCollapsedSectionBorders(
PaintInfoWithOffset paint_info_with_offset(layout_table_section_, paint_info); PaintInfoWithOffset paint_info_with_offset(layout_table_section_, paint_info);
const auto& local_paint_info = paint_info_with_offset.GetPaintInfo(); const auto& local_paint_info = paint_info_with_offset.GetPaintInfo();
auto paint_offset = paint_info_with_offset.PaintOffset(); auto paint_offset = paint_info_with_offset.PaintOffset();
BoxClipper box_clipper(layout_table_section_, local_paint_info); base::Optional<ScopedBoxClipper> box_clipper;
if (local_paint_info.phase != PaintPhase::kMask)
box_clipper.emplace(layout_table_section_, local_paint_info);
CellSpan dirtied_rows; CellSpan dirtied_rows;
CellSpan dirtied_columns; CellSpan dirtied_columns;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment