blob: 1c3d1329a0ae62044991ed480ae9dbb9a0ba2829 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "pdf/pdf_ink_brush.h"
#include <numbers>
#include <optional>
#include <utility>
#include "base/check_op.h"
#include "base/notreached.h"
#include "pdf/ink/ink_brush.h"
#include "pdf/ink/ink_brush_family.h"
#include "pdf/ink/ink_brush_paint.h"
#include "pdf/ink/ink_brush_tip.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect_conversions.h"
namespace chrome_pdf {
namespace {
std::string CreateBrushUri() {
// TODO(crbug.com/353942923): Use real value here.
return "ink://ink/texture:test-texture";
}
float GetCornerRounding(PdfInkBrush::Type type) {
switch (type) {
case PdfInkBrush::Type::kHighlighter:
return 0.0f;
case PdfInkBrush::Type::kPen:
return 1.0f;
}
NOTREACHED();
}
float GetOpacity(PdfInkBrush::Type type) {
switch (type) {
case PdfInkBrush::Type::kHighlighter:
// LINT.IfChange(HighlighterOpacity)
return 0.4f;
// LINT.ThenChange(//chrome/browser/resources/pdf/elements/viewer_side_panel.ts:HighlighterOpacity)
case PdfInkBrush::Type::kPen:
return 1.0f;
}
NOTREACHED();
}
std::unique_ptr<InkBrush> CreateInkBrush(PdfInkBrush::Type type,
PdfInkBrush::Params params) {
CHECK_GT(params.size, 0);
// TODO(crbug.com/353942923): Use real values here.
InkBrushTip tip;
tip.corner_rounding = GetCornerRounding(type);
tip.opacity_multiplier = GetOpacity(type);
InkBrushPaint::TextureLayer layer;
layer.color_texture_uri = CreateBrushUri();
layer.mapping = InkBrushPaint::TextureMapping::kWinding;
layer.size_unit = InkBrushPaint::TextureSizeUnit::kBrushSize;
layer.size_x = 3;
layer.size_y = 5;
layer.size_jitter_x = 0.1;
layer.size_jitter_y = 2;
layer.keyframes = {
{.progress = 0.1, .rotation_in_radians = std::numbers::pi_v<float> / 4}};
layer.blend_mode = InkBrushPaint::BlendMode::kSrcIn;
InkBrushPaint paint;
paint.texture_layers.push_back(layer);
auto family = InkBrushFamily::Create(std::move(tip), std::move(paint), "");
CHECK(family);
return InkBrush::Create(std::move(family),
/*color=*/params.color,
/*size=*/params.size,
/*epsilon=*/0.1f);
}
// Determine the area to invalidate centered around a point where a brush is
// applied.
gfx::Rect GetPointInvalidateArea(float brush_diameter,
const gfx::PointF& center) {
// Choose a rectangle that surrounds the point for the brush radius.
float brush_radius = brush_diameter / 2;
return gfx::ToEnclosingRect(gfx::RectF(center.x() - brush_radius,
center.y() - brush_radius,
brush_diameter, brush_diameter));
}
} // namespace
// static
std::optional<PdfInkBrush::Type> PdfInkBrush::StringToType(
const std::string& brush_type) {
if (brush_type == "highlighter") {
return Type::kHighlighter;
}
if (brush_type == "pen") {
return Type::kPen;
}
return std::nullopt;
}
// static
void PdfInkBrush::CheckToolSizeIsInRange(float size) {
CHECK_GE(size, 1);
CHECK_LE(size, 16);
}
PdfInkBrush::PdfInkBrush(Type brush_type, Params brush_params)
: ink_brush_(CreateInkBrush(brush_type, brush_params)) {
CHECK(ink_brush_);
}
PdfInkBrush::~PdfInkBrush() = default;
const InkBrush& PdfInkBrush::GetInkBrush() const {
return *ink_brush_;
}
gfx::Rect PdfInkBrush::GetInvalidateArea(const gfx::PointF& center1,
const gfx::PointF& center2) const {
// For a line connecting `center1` to `center2`, the invalidate
// region is the union between the areas affected by them both.
float brush_diameter = ink_brush_->GetSize();
gfx::Rect area1 = GetPointInvalidateArea(brush_diameter, center1);
gfx::Rect area2 = GetPointInvalidateArea(brush_diameter, center2);
area2.Union(area1);
return area2;
}
} // namespace chrome_pdf