Skip to content

Commit

Permalink
Update content implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
sammycage committed Dec 6, 2024
1 parent 60f3ad0 commit 3ee606e
Show file tree
Hide file tree
Showing 2 changed files with 327 additions and 0 deletions.
205 changes: 205 additions & 0 deletions source/layout/contentbox.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
#include "contentbox.h"
#include "replacedbox.h"
#include "imageresource.h"
#include "document.h"
#include "cssrule.h"
#include "counters.h"

namespace plutobook {

ContentBox::ContentBox(const RefPtr<BoxStyle>& style)
: TextBox(nullptr, style)
{
}

LeaderBox::LeaderBox(const RefPtr<BoxStyle>& style)
: ContentBox(style)
{
}

TargetCounterBox::TargetCounterBox(const RefPtr<BoxStyle>& style)
: ContentBox(style)
{
}

PageCounterBox::PageCounterBox(const RefPtr<BoxStyle>& style)
: ContentBox(style)
{
}

PagesCounterBox::PagesCounterBox(const RefPtr<BoxStyle>& style)
: ContentBox(style)
{
}

ContentBoxBuilder::ContentBoxBuilder(Counters& counters, Element* element, Box* box)
: m_counters(counters)
, m_element(element)
, m_parentBox(box)
, m_parentStyle(box->style())
{
}

void ContentBoxBuilder::addText(const HeapString& text)
{
if(text.empty())
return;
if(m_lastTextBox) {
m_lastTextBox->appendText(text);
return;
}

auto box = new (m_element->heap()) TextBox(nullptr, m_parentStyle);
box->setText(text);
m_parentBox->addChild(box);
m_lastTextBox = box;
}

void ContentBoxBuilder::addLeaderText(const HeapString& text)
{
if(text.empty())
return;
auto box = new (m_element->heap()) LeaderBox(m_parentStyle);
box->setText(text);
m_parentBox->addChild(box);
m_lastTextBox = nullptr;
}

void ContentBoxBuilder::addLeader(const RefPtr<CSSValue>& value)
{
static const GlobalString dotted(".");
static const GlobalString solid("_");
static const GlobalString space(" ");
if(auto string = to<CSSStringValue>(value)) {
addLeaderText(string->value());
return;
}

auto& ident = to<CSSIdentValue>(*value);
switch(ident.value()) {
case CSSValueID::Dotted:
addLeaderText(dotted);
break;
case CSSValueID::Solid:
addLeaderText(solid);
break;
case CSSValueID::Space:
addLeaderText(space);
break;
default:
assert(false);
}
}

void ContentBoxBuilder::addTargetCounter(const RefPtr<CSSFunctionValue>& function)
{
assert(function->id() == CSSValueID::TargetCounter || function->id() == CSSValueID::TargetCounters);
auto style = BoxStyle::create(*m_parentStyle, Display::Inline);
auto box = new (m_element->heap()) TargetCounterBox(style);

size_t index = 0;

if(auto attr = to<CSSUnaryFunctionValue>(function->at(index))) {
assert(attr->id() == CSSValueID::Attr);
box->setFragment(m_element->getAttribute(to<CSSCustomIdentValue>(*attr->value()).value()));
} else {
box->setFragment(to<CSSLocalUrlValue>(*function->at(index)).value());
}

++index;

box->setIdentifier(to<CSSCustomIdentValue>(*function->at(index++)).value());
if(function->id() == CSSValueID::TargetCounters)
box->setSeperator(to<CSSStringValue>(*function->at(index++)).value());
if(index < function->size()) {
box->setListStyle(to<CSSCustomIdentValue>(*function->at(index++)).value());
assert(index == function->size());
}

m_parentBox->addChild(box);
m_lastTextBox = nullptr;
}

void ContentBoxBuilder::addImage(RefPtr<Image> image)
{
if(image == nullptr)
return;
auto style = BoxStyle::create(*m_parentStyle, Display::Inline);
auto box = new (m_element->heap()) ImageBox(nullptr, style);
box->setImage(std::move(image));
m_parentBox->addChild(box);
m_lastTextBox = nullptr;
}

void ContentBoxBuilder::addQuote(CSSValueID value)
{
assert(value == CSSValueID::OpenQuote || value == CSSValueID::CloseQuote || value == CSSValueID::NoOpenQuote || value == CSSValueID::NoCloseQuote);
auto openquote = (value == CSSValueID::OpenQuote || value == CSSValueID::NoOpenQuote);
auto closequote = (value == CSSValueID::CloseQuote || value == CSSValueID::NoCloseQuote);
auto usequote = (value == CSSValueID::OpenQuote || value == CSSValueID::CloseQuote);
if(closequote && m_counters.quoteDepth())
m_counters.decreaseQuoteDepth();
if(usequote)
addText(m_parentStyle->getQuote(openquote, m_counters.quoteDepth()));
if(openquote) {
m_counters.increaseQuoteDepth();
}
}

void ContentBoxBuilder::build()
{
auto content = m_parentStyle->get(CSSPropertyID::Content);
if(content && content->id() == CSSValueID::None)
return;
if(content == nullptr || content->id() == CSSValueID::Normal) {
if(m_parentStyle->pseudoType() != PseudoType::Marker)
return;
if(auto image = m_parentStyle->listStyleImage()) {
addImage(std::move(image));
return;
}

auto listStyleType = m_parentStyle->get(CSSPropertyID::ListStyleType);
if(listStyleType == nullptr) {
static const GlobalString disc("disc");
addText(m_counters.markerText(disc));
return;
}

if(listStyleType->id() == CSSValueID::None)
return;
if(auto listStyle = to<CSSStringValue>(listStyleType)) {
addText(listStyle->value());
return;
}

auto& listStyle = to<CSSCustomIdentValue>(*listStyleType);
addText(m_counters.markerText(listStyle.value()));
return;
}

for(auto& value : to<CSSListValue>(*content)) {
if(auto string = to<CSSStringValue>(value)) {
addText(string->value());
} else if(auto image = to<CSSImageValue>(value)) {
addImage(image->fetch(m_element->document()));
} else if(auto counter = to<CSSCounterValue>(value)) {
addText(m_counters.counterText(counter->identifier(), counter->listStyle(), counter->separator()));
} else if(auto function = to<CSSFunctionValue>(value)) {
addTargetCounter(function);
} else if(auto ident = to<CSSIdentValue>(value)) {
addQuote(ident->value());
} else {
auto& function = to<CSSUnaryFunctionValue>(*value);
if(function.id() == CSSValueID::Attr) {
auto& name = to<CSSCustomIdentValue>(*function.value());
addText(m_element->getAttribute(name.value()));
} else {
assert(function.id() == CSSValueID::Leader);
addLeader(function.value());
}
}
}
}

} // namespace plutobook
122 changes: 122 additions & 0 deletions source/layout/contentbox.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#ifndef PLUTOBOOK_CONTENTBOX_H
#define PLUTOBOOK_CONTENTBOX_H

#include "globalstring.h"
#include "textbox.h"

namespace plutobook {

class ContentBox : public TextBox {
public:
ContentBox(const RefPtr<BoxStyle>& style);

bool isContentBox() const final { return true; }

const char* name() const override { return "ContentBox"; }
};

template<>
struct is_a<ContentBox> {
static bool check(const Box& box) { return box.isContentBox(); }
};

class LeaderBox final : public ContentBox {
public:
LeaderBox(const RefPtr<BoxStyle>& style);

bool isLeaderBox() const final { return true; }

const char* name() const final { return "LeaderBox"; }
};

template<>
struct is_a<LeaderBox> {
static bool check(const Box& box) { return box.isLeaderBox(); }
};

class TargetCounterBox final : public ContentBox {
public:
TargetCounterBox(const RefPtr<BoxStyle>& style);

bool isTargetCounterBox() const final { return true; }

const HeapString& fragment() const { return m_fragment; }
const GlobalString& identifier() const { return m_identifier; }
const HeapString& seperator() const { return m_seperator; }
const GlobalString& listStyle() const { return m_listStyle; }

void setFragment(const HeapString& fragment) { m_fragment = fragment; }
void setIdentifier(const GlobalString& identifier) { m_identifier = identifier; }
void setSeperator(const HeapString& seperator) { m_seperator = seperator; }
void setListStyle(const GlobalString& listStyle) { m_listStyle = listStyle; }

const char* name() const final { return "TargetCounterBox"; }

private:
HeapString m_fragment;
GlobalString m_identifier;
HeapString m_seperator;
GlobalString m_listStyle;
};

template<>
struct is_a<TargetCounterBox> {
static bool check(const Box& box) { return box.isTargetCounterBox(); }
};

class PageCounterBox final : public ContentBox{
public:
PageCounterBox(const RefPtr<BoxStyle>& style);

bool isPageCounterBox() const final { return true; }

const char* name() const final { return "PageCounterBox"; }
};

template<>
struct is_a<PageCounterBox> {
static bool check(const Box& box) { return box.isPageCounterBox(); }
};

class PagesCounterBox final : public ContentBox{
public:
PagesCounterBox(const RefPtr<BoxStyle>& style);

bool isPagesCounterBox() const final { return true; }

const char* name() const final { return "PagesCounterBox"; }
};

template<>
struct is_a<PagesCounterBox> {
static bool check(const Box& box) { return box.isPagesCounterBox(); }
};

class Counters;
class Element;
class CSSFunctionValue;

class ContentBoxBuilder {
public:
ContentBoxBuilder(Counters& counters, Element* element, Box* box);

void build();

private:
void addText(const HeapString& text);
void addLeaderText(const HeapString& text);
void addLeader(const RefPtr<CSSValue>& value);
void addTargetCounter(const RefPtr<CSSFunctionValue>& function);
void addImage(RefPtr<Image> image);
void addQuote(CSSValueID value);

Counters& m_counters;
Element* m_element;
Box* m_parentBox;
BoxStyle* m_parentStyle;
TextBox* m_lastTextBox{nullptr};
};

} // namespace plutobook

#endif // PLUTOBOOK_CONTENTBOX_H

0 comments on commit 3ee606e

Please sign in to comment.