blob: edb7d9aeb12f4201a2d55c6f4574eac47068f12f [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.
#ifndef NGBaseline_h
#define NGBaseline_h
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/fonts/font_baseline.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
namespace blink {
class LayoutBox;
class NGLayoutInputNode;
enum class NGBaselineAlgorithmType {
// Compute baselines for atomic inlines.
kAtomicInline,
// Compute baseline of first line box.
kFirstLine
};
// Baselines are products of layout.
// To compute baseline, add requests to NGConstraintSpace and run Layout().
class CORE_EXPORT NGBaselineRequest {
public:
NGBaselineRequest(NGBaselineAlgorithmType algorithm_type,
FontBaseline baseline_type)
: algorithm_type_(static_cast<unsigned>(algorithm_type)),
baseline_type_(static_cast<unsigned>(baseline_type)) {}
NGBaselineAlgorithmType AlgorithmType() const {
return static_cast<NGBaselineAlgorithmType>(algorithm_type_);
}
FontBaseline BaselineType() const {
return static_cast<FontBaseline>(baseline_type_);
}
bool operator==(const NGBaselineRequest& other) const;
bool operator!=(const NGBaselineRequest& other) const {
return !(*this == other);
}
private:
// TypeId is an integer that identifies all combinations of
// |NGBaselineRequest|. Visible only to |NGBaselineRequestList| and
// |NGBaselineList|.
static constexpr unsigned kTypeIdCount = 4;
unsigned TypeId() const { return algorithm_type_ | (baseline_type_ << 1); }
static NGBaselineRequest FromTypeId(unsigned type_id) {
DCHECK_LE(type_id, kTypeIdCount);
return NGBaselineRequest(static_cast<NGBaselineAlgorithmType>(type_id & 1),
static_cast<FontBaseline>((type_id >> 1) & 1));
}
friend class NGBaselineList;
friend class NGBaselineRequestList;
friend class NGBaselineTest;
unsigned algorithm_type_ : 1; // NGBaselineAlgorithmType
unsigned baseline_type_ : 1; // FontBaseline
};
// A list of |NGBaselineRequest| in a packed format, with similar interface as
// |Vector|.
class CORE_EXPORT NGBaselineRequestList {
public:
NGBaselineRequestList() = default;
bool IsEmpty() const { return !type_id_mask_; }
bool operator==(const NGBaselineRequestList& other) const;
void push_back(const NGBaselineRequest& request);
void AppendVector(const NGBaselineRequestList& requests);
class const_iterator {
public:
const_iterator() : type_id_(NGBaselineRequest::kTypeIdCount), mask_(0) {}
explicit const_iterator(unsigned mask) : type_id_(0), mask_(mask) {
if (!(mask_ & 1))
++(*this);
}
const NGBaselineRequest operator*() const {
return NGBaselineRequest::FromTypeId(type_id_);
}
bool operator!=(const const_iterator& other) const {
return type_id_ != other.type_id_;
}
void operator++() {
while (type_id_ < NGBaselineRequest::kTypeIdCount) {
++type_id_;
mask_ >>= 1;
if (mask_ & 1)
break;
}
}
private:
unsigned type_id_;
unsigned mask_;
};
const_iterator begin() const { return const_iterator(type_id_mask_); }
const_iterator end() const { return const_iterator(); }
private:
// Serialize/deserialize to a bit fields.
static constexpr unsigned kSerializedBits = NGBaselineRequest::kTypeIdCount;
unsigned Serialize() const { return type_id_mask_; }
explicit NGBaselineRequestList(unsigned serialized)
: type_id_mask_(serialized) {}
friend class NGConstraintSpace;
friend class NGConstraintSpaceBuilder;
unsigned type_id_mask_ = 0;
};
// Represents a computed baseline position.
struct CORE_EXPORT NGBaseline {
NGBaselineRequest request;
LayoutUnit offset;
// @return if the node needs to propagate baseline requests/results.
static bool ShouldPropagateBaselines(const NGLayoutInputNode);
static bool ShouldPropagateBaselines(LayoutBox*);
};
// A list of |NGBaseline| in a packed format, with similar interface as
// |Vector|.
class CORE_EXPORT NGBaselineList {
public:
NGBaselineList();
bool IsEmpty() const;
base::Optional<LayoutUnit> Offset(const NGBaselineRequest request) const;
void emplace_back(NGBaselineRequest request, LayoutUnit offset);
class const_iterator {
public:
explicit const_iterator(unsigned type_id, const LayoutUnit* offset)
: type_id_(type_id), offset_(offset) {
DCHECK(offset);
if (*offset == kEmptyOffset)
++(*this);
}
const_iterator()
: type_id_(NGBaselineRequest::kTypeIdCount), offset_(nullptr) {}
const NGBaseline operator*() const {
return NGBaseline{NGBaselineRequest::FromTypeId(type_id_), *offset_};
}
bool operator!=(const const_iterator& other) const {
return type_id_ != other.type_id_;
}
void operator++() {
while (type_id_ < NGBaselineRequest::kTypeIdCount) {
++type_id_;
++offset_;
if (type_id_ < NGBaselineRequest::kTypeIdCount &&
*offset_ != kEmptyOffset)
break;
}
}
private:
unsigned type_id_;
const LayoutUnit* offset_;
};
const_iterator begin() const { return const_iterator(0, offsets_); }
const_iterator end() const { return const_iterator(); }
private:
static constexpr LayoutUnit kEmptyOffset = LayoutUnit::Min();
LayoutUnit offsets_[NGBaselineRequest::kTypeIdCount];
};
} // namespace blink
#endif // NGBaseline_h