-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
327 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |