initial commit
This commit is contained in:
4
.clang-format
Normal file
4
.clang-format
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
BasedOnStyle: LLVM
|
||||||
|
UseTab: Always
|
||||||
|
IndentWidth: 4
|
||||||
|
TabWidth: 4
|
8
.clangd
Normal file
8
.clangd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
CompileFlags:
|
||||||
|
Add:
|
||||||
|
- -DSK_VULKAN
|
||||||
|
- -I/home/kenneth/dev/clef/vendor/rapidxml-1.13
|
||||||
|
- -I/home/kenneth/dev/clef/vendor/skia
|
||||||
|
- -I/home/kenneth/dev/clef/src
|
||||||
|
- -I/nix/store/dnzbfkcdc1qj805nw84xc8qpck7i8f28-glfw-3.4/include
|
||||||
|
- -I/nix/store/0nifpiwvav0p4nh67w5vzy3xfdy2m50g-libglvnd-1.7.0-dev/include
|
88
.gitignore
vendored
Normal file
88
.gitignore
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/zig,linux,windows,macos
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=zig,linux,windows,macos
|
||||||
|
|
||||||
|
### Linux ###
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
### macOS ###
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
### macOS Patch ###
|
||||||
|
# iCloud generated files
|
||||||
|
*.icloud
|
||||||
|
|
||||||
|
### Windows ###
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
### zig ###
|
||||||
|
# Zig programming language
|
||||||
|
|
||||||
|
zig-cache/
|
||||||
|
zig-out/
|
||||||
|
build/
|
||||||
|
build-*/
|
||||||
|
docgen_tmp/
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/zig,linux,windows,macos
|
||||||
|
|
9
.gitmodules
vendored
Normal file
9
.gitmodules
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[submodule "vendor/zig-xml"]
|
||||||
|
path = vendor/zig-xml
|
||||||
|
url = https://github.com/nektro/zig-xml
|
||||||
|
[submodule "vendor/depot_tools"]
|
||||||
|
path = vendor/depot_tools
|
||||||
|
url = https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||||
|
[submodule "vendor/skia"]
|
||||||
|
path = vendor/skia
|
||||||
|
url = https://skia.googlesource.com/skia.git
|
9
README.md
Normal file
9
README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# clef
|
||||||
|
|
||||||
|
clef is an experimental web engine to enable the next generation of distributed and decentralized web apps. it is not built on the existing web standard, but rather a brand new set of technologies optimized for not only static content but also interactive applications.
|
||||||
|
|
||||||
|
- clef is not just a browser, but also a cross-platform app runtime that can run web apps on demand, much like how most of the web is today.
|
||||||
|
- clef should be lightweight to minimize resource consumption while maintaining runtime performance.
|
||||||
|
- clef will have a universal VM that can execute (multithreaded) applications written in programming languages that can be compiled to the VM's bytecode. WASM is looking promising, but unsure about its performance characteristic. Also, WASM is single-threaded, so I need to somehow add multithreading support to it. or i can just build a new VM.
|
||||||
|
- all standards of clef will not only be open-source, but also feasibly sized (unlike the current web standard) so that *anyone* can build their own web engine based on the new standard.
|
||||||
|
|
65
build.sh
Executable file
65
build.sh
Executable file
@@ -0,0 +1,65 @@
|
|||||||
|
#/bin/bash
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
script_path="$(realpath $0)"
|
||||||
|
root="$(dirname $script_path)"
|
||||||
|
|
||||||
|
pushd "$(dirname $0)"
|
||||||
|
|
||||||
|
compiler=${CC:-g++}
|
||||||
|
|
||||||
|
src_files=(
|
||||||
|
src/main.cxx
|
||||||
|
src/util/random.cxx
|
||||||
|
src/layout/layout_tree.cxx
|
||||||
|
src/rendering.cxx
|
||||||
|
)
|
||||||
|
|
||||||
|
rapidxml_version="1.13"
|
||||||
|
rapidxml_flags="-I$root/vendor/rapidxml-$rapidxml_version"
|
||||||
|
|
||||||
|
skia_include="$root/vendor/skia"
|
||||||
|
skia_link="-L$root/vendor/skia/out/Static/libaudioplayer.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libbentleyottmann.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libcompression_utils_portable.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libperfetto.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libdng_sdk.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libpathkit.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libpiex.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libskcms.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libskottie.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libskparagraph.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libskresources.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libsksg.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libskshaper.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libskunicode_core.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libskunicode_icu.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libsvg.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libwuffs.a\
|
||||||
|
-L$root/vendor/skia/out/Static/libskia.a"
|
||||||
|
skia_flags="-I$skia_include -DSK_GL -DSK_GANESH"
|
||||||
|
|
||||||
|
glfw_flags=$(pkg-config --cflags --libs glfw3)
|
||||||
|
gl_flags=$(pkg-config --cflags --libs gl)
|
||||||
|
|
||||||
|
misc_lib_flags=$(pkg-config --cflags --libs libwebp libwebpmux libwebpdemux libpng libjpeg fontconfig)
|
||||||
|
|
||||||
|
common_opts="$rapidxml_flags $skia_flags $glfw_flags $gl_flags -I$root/src -Wall --std=c++20 -v -L$root/vendor/skia/out/Static -lskia -lz $misc_lib_flags"
|
||||||
|
debug_opts="--debug --optimize -DDEBUG $common_opts"
|
||||||
|
|
||||||
|
mkdir -p build
|
||||||
|
pushd build >> /dev/null
|
||||||
|
|
||||||
|
all_src=""
|
||||||
|
for p in "${src_files[@]}"; do
|
||||||
|
all_src+=" ../${p}"
|
||||||
|
done
|
||||||
|
|
||||||
|
compile="$compiler $all_src -o clef $debug_opts"
|
||||||
|
|
||||||
|
echo $compile
|
||||||
|
$compile
|
||||||
|
|
||||||
|
popd >> /dev/null
|
||||||
|
popd >> /dev/null
|
||||||
|
|
21
configure.sh
Executable file
21
configure.sh
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#/bin/bash
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
script_path="$(realpath $0)"
|
||||||
|
root="$(dirname $script_path)"
|
||||||
|
pushd "$(dirname "$0")" > /dev/null
|
||||||
|
|
||||||
|
glfw_include=$(pkg-config --cflags glfw3)
|
||||||
|
gl_include=$(pkg-config --cflags gl)
|
||||||
|
|
||||||
|
cat > .clangd <<- EOF
|
||||||
|
CompileFlags:
|
||||||
|
Add:
|
||||||
|
- -DSK_VULKAN
|
||||||
|
- -I$root/vendor/rapidxml-1.13
|
||||||
|
- -I$root/vendor/skia
|
||||||
|
- -I$root/src
|
||||||
|
- $glfw_include
|
||||||
|
- $gl_include
|
||||||
|
EOF
|
76
flake.lock
generated
Normal file
76
flake.lock
generated
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1659877975,
|
||||||
|
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixgl": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1713543440,
|
||||||
|
"narHash": "sha256-lnzZQYG0+EXl/6NkGpyIz+FEOc/DSEG57AP1VsdeNrM=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixGL",
|
||||||
|
"rev": "310f8e49a149e4c9ea52f1adf70cdc768ec53f8a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixGL",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1660551188,
|
||||||
|
"narHash": "sha256-a1LARMMYQ8DPx1BgoI/UN4bXe12hhZkCNqdxNi6uS0g=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "441dc5d512153039f19ef198e662e4f3dbb9fd65",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1728151769,
|
||||||
|
"narHash": "sha256-tNzxIHhjdKWyMP5KpJwDk90eLPzioyIL8MITjfCHo+s=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "b1ce757d3e75d5886dc04d3e51d8cb55ad321cc1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixgl": "nixgl",
|
||||||
|
"nixpkgs": "nixpkgs_2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
55
flake.nix
Normal file
55
flake.nix
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
description = "Next generation web engine";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs?tag=24.05";
|
||||||
|
nixgl.url = "github:nix-community/nixGL";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, nixgl, ... }:
|
||||||
|
let
|
||||||
|
supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];
|
||||||
|
|
||||||
|
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
||||||
|
|
||||||
|
nixpkgsFor = forAllSystems (system:
|
||||||
|
import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
overlays = [ nixgl.overlay ];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells = forAllSystems (system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgsFor.${system};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
default = pkgs.mkShell {
|
||||||
|
packages = [
|
||||||
|
pkgs.python312
|
||||||
|
pkgs.gcc
|
||||||
|
pkgs.pkg-config
|
||||||
|
pkgs.clang
|
||||||
|
pkgs.clang-tools
|
||||||
|
pkgs.nixgl.auto.nixGLDefault
|
||||||
|
|
||||||
|
# required by skia
|
||||||
|
pkgs.libjpeg
|
||||||
|
pkgs.zlib
|
||||||
|
pkgs.fontconfig
|
||||||
|
pkgs.expat
|
||||||
|
pkgs.glfw
|
||||||
|
pkgs.libGLU
|
||||||
|
pkgs.mesa
|
||||||
|
pkgs.xorg.libX11
|
||||||
|
pkgs.libwebp
|
||||||
|
pkgs.icu
|
||||||
|
];
|
||||||
|
|
||||||
|
shellHook = "export CC=clang++";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
BIN
resources/font/Inter/Inter-Black.otf
Normal file
BIN
resources/font/Inter/Inter-Black.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-BlackItalic.otf
Normal file
BIN
resources/font/Inter/Inter-BlackItalic.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-Bold.otf
Normal file
BIN
resources/font/Inter/Inter-Bold.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-BoldItalic.otf
Normal file
BIN
resources/font/Inter/Inter-BoldItalic.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-ExtraBold.otf
Normal file
BIN
resources/font/Inter/Inter-ExtraBold.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-ExtraBoldItalic.otf
Normal file
BIN
resources/font/Inter/Inter-ExtraBoldItalic.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-ExtraLight.otf
Normal file
BIN
resources/font/Inter/Inter-ExtraLight.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-ExtraLightItalic.otf
Normal file
BIN
resources/font/Inter/Inter-ExtraLightItalic.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-Italic.otf
Normal file
BIN
resources/font/Inter/Inter-Italic.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-Light.otf
Normal file
BIN
resources/font/Inter/Inter-Light.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-LightItalic.otf
Normal file
BIN
resources/font/Inter/Inter-LightItalic.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-Medium.otf
Normal file
BIN
resources/font/Inter/Inter-Medium.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-MediumItalic.otf
Normal file
BIN
resources/font/Inter/Inter-MediumItalic.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-Regular.otf
Normal file
BIN
resources/font/Inter/Inter-Regular.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-SemiBold.otf
Normal file
BIN
resources/font/Inter/Inter-SemiBold.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-SemiBoldItalic.otf
Normal file
BIN
resources/font/Inter/Inter-SemiBoldItalic.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-Thin.otf
Normal file
BIN
resources/font/Inter/Inter-Thin.otf
Normal file
Binary file not shown.
BIN
resources/font/Inter/Inter-ThinItalic.otf
Normal file
BIN
resources/font/Inter/Inter-ThinItalic.otf
Normal file
Binary file not shown.
137
src/layout/layout_tree.cxx
Normal file
137
src/layout/layout_tree.cxx
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
#include "layout_tree.hxx"
|
||||||
|
#include "include/core/SkFont.h"
|
||||||
|
#include "include/core/SkFontMgr.h"
|
||||||
|
#include "include/core/SkFontTypes.h"
|
||||||
|
#include "include/core/SkRect.h"
|
||||||
|
#include "include/core/SkRefCnt.h"
|
||||||
|
#include "include/core/SkTypeface.h"
|
||||||
|
#include "rapidxml.hpp"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <limits>
|
||||||
|
#include <random>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
static std::uniform_int_distribution<std::mt19937::result_type>
|
||||||
|
random_id(0, std::numeric_limits<std::mt19937::result_type>::max());
|
||||||
|
static std::random_device dev;
|
||||||
|
static std::mt19937 rng(dev());
|
||||||
|
|
||||||
|
uint64_t __generate_random_node_id() { return random_id(rng); };
|
||||||
|
|
||||||
|
Clef::ContainerNode::ContainerNode() {
|
||||||
|
prev_sibiling = nullptr;
|
||||||
|
next_sibiling = nullptr;
|
||||||
|
parent = nullptr;
|
||||||
|
type = Clef::LayoutTree::NodeType::Container;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clef::LayoutBound Clef::ContainerNode::measure() {
|
||||||
|
float max_child_width = -1;
|
||||||
|
float total_height = 0;
|
||||||
|
for (const auto &child : children) {
|
||||||
|
const auto bound = child->measure();
|
||||||
|
std::cout << "bound width" << bound.width << " height " << bound.height
|
||||||
|
<< std::endl;
|
||||||
|
if (bound.width > max_child_width) {
|
||||||
|
max_child_width = bound.width;
|
||||||
|
}
|
||||||
|
total_height += bound.height;
|
||||||
|
}
|
||||||
|
return {0, 0, max_child_width, total_height};
|
||||||
|
}
|
||||||
|
|
||||||
|
Clef::TextNode::TextNode(const char *content, SkFont font)
|
||||||
|
: content(content), font(font) {
|
||||||
|
prev_sibiling = nullptr;
|
||||||
|
next_sibiling = nullptr;
|
||||||
|
parent = nullptr;
|
||||||
|
type = Clef::LayoutTree::NodeType::Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clef::LayoutBound Clef::TextNode::measure() {
|
||||||
|
SkRect rect;
|
||||||
|
font.measureText(content.c_str(), content.size(), SkTextEncoding::kUTF8,
|
||||||
|
&rect);
|
||||||
|
return {0, 0, rect.width(), rect.height()};
|
||||||
|
}
|
||||||
|
|
||||||
|
Clef::LayoutTree::LayoutTree(Clef::LayoutTree::Node *root) : root(root) {}
|
||||||
|
|
||||||
|
Clef::LayoutTree::Node *
|
||||||
|
Clef::LayoutTree::Node::from_xml_node(rapidxml::xml_node<char> *node,
|
||||||
|
const SkFontMgr &font_mgr) {
|
||||||
|
std::cout << "encountered node:" << node->name() << std::endl;
|
||||||
|
|
||||||
|
if (std::strncmp("box", node->name(), 3) == 0) {
|
||||||
|
auto container_node = new ContainerNode();
|
||||||
|
container_node->id = __generate_random_node_id();
|
||||||
|
|
||||||
|
std::cout << "assigned id " << container_node->id << std::endl;
|
||||||
|
auto current_node = node->first_node();
|
||||||
|
Node *last_node;
|
||||||
|
|
||||||
|
while (current_node) {
|
||||||
|
auto n = Node::from_xml_node(current_node, font_mgr);
|
||||||
|
if (!n) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_node) {
|
||||||
|
n->prev_sibiling = last_node;
|
||||||
|
last_node->next_sibiling = n;
|
||||||
|
std::cout << n << std::endl;
|
||||||
|
std::cout << last_node << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
n->parent = container_node;
|
||||||
|
container_node->children.emplace_back(n);
|
||||||
|
|
||||||
|
last_node = n;
|
||||||
|
current_node = current_node->next_sibling();
|
||||||
|
}
|
||||||
|
|
||||||
|
return container_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::strncmp("text", node->name(), 4) == 0) {
|
||||||
|
const auto content = node->value();
|
||||||
|
if (!content) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto typeface =
|
||||||
|
font_mgr.matchFamilyStyle("Inter", SkFontStyle::Normal());
|
||||||
|
SkFont f(typeface, 20);
|
||||||
|
|
||||||
|
auto n = new TextNode(content, f);
|
||||||
|
n->id = __generate_random_node_id();
|
||||||
|
|
||||||
|
std::cout << "assigned id " << n->id << std::endl;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clef::LayoutTree Clef::LayoutTree::from_xml(const rapidxml::xml_document<> &doc,
|
||||||
|
const SkFontMgr &font_mgr) {
|
||||||
|
Clef::LayoutTree::Node *root;
|
||||||
|
|
||||||
|
auto xml_root = doc.first_node("box");
|
||||||
|
if (!xml_root) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"cml layout must start with a container node.");
|
||||||
|
}
|
||||||
|
|
||||||
|
root = Node::from_xml_node(xml_root, font_mgr);
|
||||||
|
if (!root) {
|
||||||
|
throw std::runtime_error("failed to parse cml");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "cml parsed successfully" << std::endl;
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
65
src/layout/layout_tree.hxx
Normal file
65
src/layout/layout_tree.hxx
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#ifndef __CLEF_LAYOUT_LAYOUT_TREE_HXX__
|
||||||
|
#define __CLEF_LAYOUT_LAYOUT_TREE_HXX__
|
||||||
|
|
||||||
|
#include "include/core/SkFont.h"
|
||||||
|
#include "include/core/SkRefCnt.h"
|
||||||
|
#include "include/core/SkTypeface.h"
|
||||||
|
#include "rapidxml.hpp"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Clef {
|
||||||
|
|
||||||
|
struct LayoutBound {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float width;
|
||||||
|
float height;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LayoutTree {
|
||||||
|
enum class NodeType { Text, Container };
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
uint64_t id;
|
||||||
|
Node *parent;
|
||||||
|
Node *prev_sibiling;
|
||||||
|
Node *next_sibiling;
|
||||||
|
NodeType type;
|
||||||
|
|
||||||
|
static Node *from_xml_node(rapidxml::xml_node<char> *node,
|
||||||
|
const SkFontMgr &font_mgr);
|
||||||
|
|
||||||
|
virtual Clef::LayoutBound measure() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Node *root;
|
||||||
|
|
||||||
|
static LayoutTree from_xml(const rapidxml::xml_document<> &doc,
|
||||||
|
const SkFontMgr &font_mgr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
LayoutTree(Node *root);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ContainerNode : LayoutTree::Node {
|
||||||
|
std::vector<Node *> children;
|
||||||
|
|
||||||
|
Clef::LayoutBound measure() override;
|
||||||
|
|
||||||
|
ContainerNode();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextNode : LayoutTree::Node {
|
||||||
|
std::string content;
|
||||||
|
SkFont font;
|
||||||
|
|
||||||
|
Clef::LayoutBound measure() override;
|
||||||
|
|
||||||
|
TextNode(const char *content, SkFont font);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Clef
|
||||||
|
|
||||||
|
#endif
|
149
src/main.cxx
Normal file
149
src/main.cxx
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
#include "GL/gl.h"
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
#include "include/core/SkCanvas.h"
|
||||||
|
#include "include/core/SkColor.h"
|
||||||
|
#include "include/core/SkColorType.h"
|
||||||
|
#include "include/core/SkFontStyle.h"
|
||||||
|
#include "include/core/SkPaint.h"
|
||||||
|
#include "include/core/SkTypeface.h"
|
||||||
|
#include "include/gpu/ganesh/GrDirectContext.h"
|
||||||
|
#include "include/gpu/ganesh/GrTypes.h"
|
||||||
|
#include "include/gpu/ganesh/gl/GrGLTypes.h"
|
||||||
|
#include "layout/layout_tree.hxx"
|
||||||
|
#include "rapidxml.hpp"
|
||||||
|
#include "rendering.hxx"
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <fstream>
|
||||||
|
#include <include/core/SkColorSpace.h>
|
||||||
|
#include <include/core/SkFont.h>
|
||||||
|
#include <include/core/SkFontMgr.h>
|
||||||
|
#include <include/core/SkStream.h>
|
||||||
|
#include <include/gpu/ganesh/GrBackendSurface.h>
|
||||||
|
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
|
||||||
|
#include <include/gpu/ganesh/gl/GrGLAssembleInterface.h>
|
||||||
|
#include <include/gpu/ganesh/gl/GrGLBackendSurface.h>
|
||||||
|
#include <include/gpu/ganesh/gl/GrGLDirectContext.h>
|
||||||
|
#include <include/gpu/ganesh/gl/GrGLInterface.h>
|
||||||
|
#include <include/ports/SkFontMgr_directory.h>
|
||||||
|
#include <include/utils/SkCustomTypeface.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <rapidxml_utils.hpp>
|
||||||
|
|
||||||
|
void framebuffer_size_callback(GLFWwindow *window, int width, int height) {
|
||||||
|
GLFWmonitor *mon = glfwGetPrimaryMonitor();
|
||||||
|
float xscale, yscale;
|
||||||
|
glfwGetMonitorContentScale(mon, &xscale, &yscale);
|
||||||
|
glViewport(0, 0, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc <= 0) {
|
||||||
|
std::cerr << "expected a markup file" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWwindow *window;
|
||||||
|
|
||||||
|
if (!glfwInit()) {
|
||||||
|
std::cout << "failed to initialize glfw" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
window = glfwCreateWindow(200, 200, "Clef", nullptr, nullptr);
|
||||||
|
if (!window) {
|
||||||
|
std::cout << "window cannot be created" << std::endl;
|
||||||
|
glfwTerminate();
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE);
|
||||||
|
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
|
||||||
|
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
||||||
|
|
||||||
|
glfwMakeContextCurrent(window);
|
||||||
|
|
||||||
|
auto interface = GrGLMakeNativeInterface();
|
||||||
|
if (!interface) {
|
||||||
|
interface = GrGLMakeAssembledInterface(
|
||||||
|
nullptr, (GrGLGetProc) * [](void *, const char *p) -> void * {
|
||||||
|
return (void *)glfwGetProcAddress(p);
|
||||||
|
});
|
||||||
|
if (!interface) {
|
||||||
|
std::cout << "failed to make native interface" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto context = GrDirectContexts::MakeGL(interface);
|
||||||
|
if (!context) {
|
||||||
|
std::cout << "failed to make DirectContext" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "gl direct context created" << std::endl;
|
||||||
|
|
||||||
|
GrGLFramebufferInfo framebufferInfo;
|
||||||
|
framebufferInfo.fFBOID = 0;
|
||||||
|
framebufferInfo.fFormat = GL_RGBA8;
|
||||||
|
|
||||||
|
std::cout << "frame buffer info created" << std::endl;
|
||||||
|
|
||||||
|
SkColorType colorType = kRGBA_8888_SkColorType;
|
||||||
|
auto target =
|
||||||
|
GrBackendRenderTargets::MakeGL(400, 400, 0, 0, framebufferInfo);
|
||||||
|
|
||||||
|
auto skSurface = SkSurfaces::WrapBackendRenderTarget(
|
||||||
|
context.get(), target, kBottomLeft_GrSurfaceOrigin, colorType, nullptr,
|
||||||
|
nullptr);
|
||||||
|
if (!skSurface) {
|
||||||
|
std::cout << "failed to create skia surface" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "skia surface created" << std::endl;
|
||||||
|
|
||||||
|
SkCanvas *canvas = skSurface->getCanvas();
|
||||||
|
if (!canvas) {
|
||||||
|
std::cout << "failed to obtain skia canvas" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwSwapInterval(1);
|
||||||
|
|
||||||
|
std::cout << "canvas obtained. entering run loop..." << std::endl;
|
||||||
|
|
||||||
|
auto fontMgr = SkFontMgr_New_Custom_Directory("../resources/font/Inter");
|
||||||
|
std::cout << "fonts found: " << fontMgr->countFamilies() << std::endl;
|
||||||
|
|
||||||
|
auto interRegular =
|
||||||
|
fontMgr->matchFamilyStyle("Inter", SkFontStyle::Normal());
|
||||||
|
if (!interRegular) {
|
||||||
|
std::cout << "WARNING: inter regular not found" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidxml::file<> input_file(argv[1]);
|
||||||
|
rapidxml::xml_document<> doc;
|
||||||
|
doc.parse<rapidxml::parse_default>(input_file.data());
|
||||||
|
|
||||||
|
Clef::RenderingContext ctx{
|
||||||
|
.canvas = canvas,
|
||||||
|
.font_mgr = fontMgr,
|
||||||
|
};
|
||||||
|
|
||||||
|
Clef::LayoutTree tree = Clef::LayoutTree::from_xml(doc, *fontMgr.get());
|
||||||
|
|
||||||
|
while (!glfwWindowShouldClose(window)) {
|
||||||
|
Clef::render_tree(ctx, tree);
|
||||||
|
|
||||||
|
context->flush();
|
||||||
|
|
||||||
|
glfwSwapBuffers(window);
|
||||||
|
glfwPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwDestroyWindow(window);
|
||||||
|
glfwTerminate();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
99
src/rendering.cxx
Normal file
99
src/rendering.cxx
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#include "rendering.hxx"
|
||||||
|
#include "include/core/SkCanvas.h"
|
||||||
|
#include "include/core/SkColor.h"
|
||||||
|
#include "include/core/SkFont.h"
|
||||||
|
#include "include/core/SkPaint.h"
|
||||||
|
#include "include/core/SkRect.h"
|
||||||
|
#include "include/core/SkSurfaceProps.h"
|
||||||
|
#include "layout/layout_tree.hxx"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <limits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
inline const auto NODE_TYPE_BOX = "box";
|
||||||
|
inline const auto NODE_TYPE_TEXT = "text";
|
||||||
|
|
||||||
|
Clef::RenderingContext new_rendering_context(SkCanvas *canvas,
|
||||||
|
sk_sp<SkFontMgr> font_mgr) {
|
||||||
|
return {
|
||||||
|
.canvas = canvas,
|
||||||
|
.layout_map{},
|
||||||
|
.font_mgr = font_mgr,
|
||||||
|
.random_id{0, std::numeric_limits<uint64_t>::max()},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Clef::LayoutBound __calculate_node_position(Clef::RenderingContext &ctx,
|
||||||
|
Clef::LayoutTree::Node *node) {
|
||||||
|
auto bounds = node->measure();
|
||||||
|
if (!node->parent) {
|
||||||
|
return {0, 0, bounds.width, bounds.height};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->prev_sibiling != nullptr) {
|
||||||
|
const auto entry = ctx.layout_map.find(node->prev_sibiling->id);
|
||||||
|
if (entry == ctx.layout_map.end()) {
|
||||||
|
return {0, 0, bounds.width, bounds.height};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto prev_bound = entry->second;
|
||||||
|
return {prev_bound.x, prev_bound.y + prev_bound.height, bounds.width,
|
||||||
|
bounds.height};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto entry = ctx.layout_map.find(node->parent->id);
|
||||||
|
if (entry == ctx.layout_map.end()) {
|
||||||
|
return {0, 0, bounds.width, bounds.height};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto parent_bound = entry->second;
|
||||||
|
return {parent_bound.x, parent_bound.y, bounds.width, bounds.height};
|
||||||
|
}
|
||||||
|
|
||||||
|
void clef_render_node(Clef::RenderingContext &ctx,
|
||||||
|
Clef::LayoutTree::Node *node) {
|
||||||
|
|
||||||
|
switch (node->type) {
|
||||||
|
case Clef::LayoutTree::NodeType::Text: {
|
||||||
|
const auto pos = __calculate_node_position(ctx, node);
|
||||||
|
auto tn = static_cast<Clef::TextNode *>(node);
|
||||||
|
SkPaint paint;
|
||||||
|
paint.setColor(SK_ColorBLACK);
|
||||||
|
std::cout << "rendering text: " << tn->content << " at x = " << pos.x
|
||||||
|
<< " y = " << pos.y << std::endl;
|
||||||
|
ctx.canvas->drawString(tn->content.c_str(), pos.x, pos.y + pos.height,
|
||||||
|
tn->font, paint);
|
||||||
|
ctx.layout_map.insert({node->id, pos});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Clef::LayoutTree::NodeType::Container: {
|
||||||
|
auto cn = static_cast<Clef::ContainerNode *>(node);
|
||||||
|
const auto pos = __calculate_node_position(ctx, node);
|
||||||
|
SkRect rect{pos.x, pos.y, pos.x + pos.width, pos.y + pos.height};
|
||||||
|
SkPaint paint;
|
||||||
|
paint.setColor(SK_ColorCYAN);
|
||||||
|
ctx.canvas->drawRect(rect, paint);
|
||||||
|
ctx.layout_map.insert({node->id, pos});
|
||||||
|
|
||||||
|
for (const auto &child : cn->children) {
|
||||||
|
clef_render_node(ctx, child);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clef::render_tree(Clef::RenderingContext &ctx, const LayoutTree &tree) {
|
||||||
|
SkPaint paint;
|
||||||
|
paint.setColor(SK_ColorWHITE);
|
||||||
|
ctx.canvas->drawPaint(paint);
|
||||||
|
|
||||||
|
paint.setColor(SK_ColorBLACK);
|
||||||
|
auto tf = ctx.font_mgr->matchFamilyStyle("Inter", SkFontStyle::Normal());
|
||||||
|
SkFont f(tf, 20);
|
||||||
|
ctx.canvas->drawString("hello", 0, 10, f, paint);
|
||||||
|
|
||||||
|
clef_render_node(ctx, tree.root);
|
||||||
|
}
|
34
src/rendering.hxx
Normal file
34
src/rendering.hxx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef __CLEF__RENDERING_HXX__
|
||||||
|
#define __CLEF__RENDERING_HXX__
|
||||||
|
|
||||||
|
#include "include/core/SkCanvas.h"
|
||||||
|
#include "include/core/SkFontMgr.h"
|
||||||
|
#include "include/core/SkFontStyle.h"
|
||||||
|
#include "include/core/SkRefCnt.h"
|
||||||
|
#include "include/core/SkScalar.h"
|
||||||
|
#include "layout/layout_tree.hxx"
|
||||||
|
#include "rapidxml.hpp"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <random>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace Clef {
|
||||||
|
|
||||||
|
struct RenderingContext {
|
||||||
|
SkCanvas *canvas;
|
||||||
|
std::unordered_map<uint64_t, LayoutBound> layout_map;
|
||||||
|
sk_sp<SkFontMgr> font_mgr;
|
||||||
|
std::uniform_int_distribution<std::mt19937::result_type> random_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
RenderingContext new_rendering_context(SkCanvas *canvas,
|
||||||
|
sk_sp<SkFontMgr> font_mgr);
|
||||||
|
|
||||||
|
void render_document(RenderingContext &ctx,
|
||||||
|
const rapidxml::xml_document<> &doc);
|
||||||
|
|
||||||
|
void render_tree(RenderingContext &ctx, const LayoutTree &tree);
|
||||||
|
|
||||||
|
}; // namespace Clef
|
||||||
|
|
||||||
|
#endif
|
7
src/util/random.cxx
Normal file
7
src/util/random.cxx
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include "random.hxx"
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
static std::random_device dev;
|
||||||
|
static std::mt19937 rng(dev());
|
||||||
|
|
||||||
|
std::mt19937 Clef::get_rng() { return rng; }
|
11
src/util/random.hxx
Normal file
11
src/util/random.hxx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef __CLEF_UTIL_RANDOM_HXX__
|
||||||
|
#define __CLEF_UTIL_RANDOM_HXX__
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
namespace Clef {
|
||||||
|
|
||||||
|
std::mt19937 get_rng();
|
||||||
|
|
||||||
|
} // namespace Clef
|
||||||
|
|
||||||
|
#endif
|
4
test_cml/hello.cml
Normal file
4
test_cml/hello.cml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<box>
|
||||||
|
<text level="1">hello from clef</text>
|
||||||
|
<text>this is rendered from hello.cml</text>
|
||||||
|
</box>
|
1
vendor/depot_tools
vendored
Submodule
1
vendor/depot_tools
vendored
Submodule
Submodule vendor/depot_tools added at 5304f2bbb3
52
vendor/rapidxml-1.13/license.txt
vendored
Normal file
52
vendor/rapidxml-1.13/license.txt
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
Use of this software is granted under one of the following two licenses,
|
||||||
|
to be chosen freely by the user.
|
||||||
|
|
||||||
|
1. Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
Copyright (c) 2006, 2007 Marcin Kalicinski
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
2. The MIT License
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
Copyright (c) 2006, 2007 Marcin Kalicinski
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
IN THE SOFTWARE.
|
406
vendor/rapidxml-1.13/manual.html
vendored
Normal file
406
vendor/rapidxml-1.13/manual.html
vendored
Normal file
File diff suppressed because one or more lines are too long
2596
vendor/rapidxml-1.13/rapidxml.hpp
vendored
Normal file
2596
vendor/rapidxml-1.13/rapidxml.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
174
vendor/rapidxml-1.13/rapidxml_iterators.hpp
vendored
Normal file
174
vendor/rapidxml-1.13/rapidxml_iterators.hpp
vendored
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||||
|
#define RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||||
|
|
||||||
|
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||||
|
// Version 1.13
|
||||||
|
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||||
|
//! \file rapidxml_iterators.hpp This file contains rapidxml iterators
|
||||||
|
|
||||||
|
#include "rapidxml.hpp"
|
||||||
|
|
||||||
|
namespace rapidxml
|
||||||
|
{
|
||||||
|
|
||||||
|
//! Iterator of child nodes of xml_node
|
||||||
|
template<class Ch>
|
||||||
|
class node_iterator
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef typename xml_node<Ch> value_type;
|
||||||
|
typedef typename xml_node<Ch> &reference;
|
||||||
|
typedef typename xml_node<Ch> *pointer;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef std::bidirectional_iterator_tag iterator_category;
|
||||||
|
|
||||||
|
node_iterator()
|
||||||
|
: m_node(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
node_iterator(xml_node<Ch> *node)
|
||||||
|
: m_node(node->first_node())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
reference operator *() const
|
||||||
|
{
|
||||||
|
assert(m_node);
|
||||||
|
return *m_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer operator->() const
|
||||||
|
{
|
||||||
|
assert(m_node);
|
||||||
|
return m_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_iterator& operator++()
|
||||||
|
{
|
||||||
|
assert(m_node);
|
||||||
|
m_node = m_node->next_sibling();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_iterator operator++(int)
|
||||||
|
{
|
||||||
|
node_iterator tmp = *this;
|
||||||
|
++this;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_iterator& operator--()
|
||||||
|
{
|
||||||
|
assert(m_node && m_node->previous_sibling());
|
||||||
|
m_node = m_node->previous_sibling();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_iterator operator--(int)
|
||||||
|
{
|
||||||
|
node_iterator tmp = *this;
|
||||||
|
++this;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator ==(const node_iterator<Ch> &rhs)
|
||||||
|
{
|
||||||
|
return m_node == rhs.m_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=(const node_iterator<Ch> &rhs)
|
||||||
|
{
|
||||||
|
return m_node != rhs.m_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
xml_node<Ch> *m_node;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Iterator of child attributes of xml_node
|
||||||
|
template<class Ch>
|
||||||
|
class attribute_iterator
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef typename xml_attribute<Ch> value_type;
|
||||||
|
typedef typename xml_attribute<Ch> &reference;
|
||||||
|
typedef typename xml_attribute<Ch> *pointer;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef std::bidirectional_iterator_tag iterator_category;
|
||||||
|
|
||||||
|
attribute_iterator()
|
||||||
|
: m_attribute(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute_iterator(xml_node<Ch> *node)
|
||||||
|
: m_attribute(node->first_attribute())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
reference operator *() const
|
||||||
|
{
|
||||||
|
assert(m_attribute);
|
||||||
|
return *m_attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer operator->() const
|
||||||
|
{
|
||||||
|
assert(m_attribute);
|
||||||
|
return m_attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute_iterator& operator++()
|
||||||
|
{
|
||||||
|
assert(m_attribute);
|
||||||
|
m_attribute = m_attribute->next_attribute();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute_iterator operator++(int)
|
||||||
|
{
|
||||||
|
attribute_iterator tmp = *this;
|
||||||
|
++this;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute_iterator& operator--()
|
||||||
|
{
|
||||||
|
assert(m_attribute && m_attribute->previous_attribute());
|
||||||
|
m_attribute = m_attribute->previous_attribute();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute_iterator operator--(int)
|
||||||
|
{
|
||||||
|
attribute_iterator tmp = *this;
|
||||||
|
++this;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator ==(const attribute_iterator<Ch> &rhs)
|
||||||
|
{
|
||||||
|
return m_attribute == rhs.m_attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=(const attribute_iterator<Ch> &rhs)
|
||||||
|
{
|
||||||
|
return m_attribute != rhs.m_attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
xml_attribute<Ch> *m_attribute;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
421
vendor/rapidxml-1.13/rapidxml_print.hpp
vendored
Normal file
421
vendor/rapidxml-1.13/rapidxml_print.hpp
vendored
Normal file
@@ -0,0 +1,421 @@
|
|||||||
|
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
|
||||||
|
#define RAPIDXML_PRINT_HPP_INCLUDED
|
||||||
|
|
||||||
|
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||||
|
// Version 1.13
|
||||||
|
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||||
|
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
|
||||||
|
|
||||||
|
#include "rapidxml.hpp"
|
||||||
|
|
||||||
|
// Only include streams if not disabled
|
||||||
|
#ifndef RAPIDXML_NO_STREAMS
|
||||||
|
#include <ostream>
|
||||||
|
#include <iterator>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace rapidxml
|
||||||
|
{
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// Printing flags
|
||||||
|
|
||||||
|
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// Internal
|
||||||
|
|
||||||
|
//! \cond internal
|
||||||
|
namespace internal
|
||||||
|
{
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Internal character operations
|
||||||
|
|
||||||
|
// Copy characters from given range to given output iterator
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
|
||||||
|
{
|
||||||
|
while (begin != end)
|
||||||
|
*out++ = *begin++;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy characters from given range to given output iterator and expand
|
||||||
|
// characters into references (< > ' " &)
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
|
||||||
|
{
|
||||||
|
while (begin != end)
|
||||||
|
{
|
||||||
|
if (*begin == noexpand)
|
||||||
|
{
|
||||||
|
*out++ = *begin; // No expansion, copy character
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (*begin)
|
||||||
|
{
|
||||||
|
case Ch('<'):
|
||||||
|
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||||
|
break;
|
||||||
|
case Ch('>'):
|
||||||
|
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||||
|
break;
|
||||||
|
case Ch('\''):
|
||||||
|
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
|
||||||
|
break;
|
||||||
|
case Ch('"'):
|
||||||
|
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||||
|
break;
|
||||||
|
case Ch('&'):
|
||||||
|
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*out++ = *begin; // No expansion, copy character
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++begin; // Step to next character
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill given output iterator with repetitions of the same character
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt fill_chars(OutIt out, int n, Ch ch)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
*out++ = ch;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find character
|
||||||
|
template<class Ch, Ch ch>
|
||||||
|
inline bool find_char(const Ch *begin, const Ch *end)
|
||||||
|
{
|
||||||
|
while (begin != end)
|
||||||
|
if (*begin++ == ch)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Internal printing operations
|
||||||
|
|
||||||
|
// Print node
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||||
|
{
|
||||||
|
// Print proper node type
|
||||||
|
switch (node->type())
|
||||||
|
{
|
||||||
|
|
||||||
|
// Document
|
||||||
|
case node_document:
|
||||||
|
out = print_children(out, node, flags, indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Element
|
||||||
|
case node_element:
|
||||||
|
out = print_element_node(out, node, flags, indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Data
|
||||||
|
case node_data:
|
||||||
|
out = print_data_node(out, node, flags, indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// CDATA
|
||||||
|
case node_cdata:
|
||||||
|
out = print_cdata_node(out, node, flags, indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Declaration
|
||||||
|
case node_declaration:
|
||||||
|
out = print_declaration_node(out, node, flags, indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
case node_comment:
|
||||||
|
out = print_comment_node(out, node, flags, indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Doctype
|
||||||
|
case node_doctype:
|
||||||
|
out = print_doctype_node(out, node, flags, indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Pi
|
||||||
|
case node_pi:
|
||||||
|
out = print_pi_node(out, node, flags, indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Unknown
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If indenting not disabled, add line break after node
|
||||||
|
if (!(flags & print_no_indenting))
|
||||||
|
*out = Ch('\n'), ++out;
|
||||||
|
|
||||||
|
// Return modified iterator
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print children of the node
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||||
|
{
|
||||||
|
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
|
||||||
|
out = print_node(out, child, flags, indent);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print attributes of the node
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
|
||||||
|
{
|
||||||
|
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
|
||||||
|
{
|
||||||
|
if (attribute->name() && attribute->value())
|
||||||
|
{
|
||||||
|
// Print attribute name
|
||||||
|
*out = Ch(' '), ++out;
|
||||||
|
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
|
||||||
|
*out = Ch('='), ++out;
|
||||||
|
// Print attribute value using appropriate quote type
|
||||||
|
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
|
||||||
|
{
|
||||||
|
*out = Ch('\''), ++out;
|
||||||
|
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
|
||||||
|
*out = Ch('\''), ++out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*out = Ch('"'), ++out;
|
||||||
|
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
|
||||||
|
*out = Ch('"'), ++out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print data node
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||||
|
{
|
||||||
|
assert(node->type() == node_data);
|
||||||
|
if (!(flags & print_no_indenting))
|
||||||
|
out = fill_chars(out, indent, Ch('\t'));
|
||||||
|
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print data node
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||||
|
{
|
||||||
|
assert(node->type() == node_cdata);
|
||||||
|
if (!(flags & print_no_indenting))
|
||||||
|
out = fill_chars(out, indent, Ch('\t'));
|
||||||
|
*out = Ch('<'); ++out;
|
||||||
|
*out = Ch('!'); ++out;
|
||||||
|
*out = Ch('['); ++out;
|
||||||
|
*out = Ch('C'); ++out;
|
||||||
|
*out = Ch('D'); ++out;
|
||||||
|
*out = Ch('A'); ++out;
|
||||||
|
*out = Ch('T'); ++out;
|
||||||
|
*out = Ch('A'); ++out;
|
||||||
|
*out = Ch('['); ++out;
|
||||||
|
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||||
|
*out = Ch(']'); ++out;
|
||||||
|
*out = Ch(']'); ++out;
|
||||||
|
*out = Ch('>'); ++out;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print element node
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||||
|
{
|
||||||
|
assert(node->type() == node_element);
|
||||||
|
|
||||||
|
// Print element name and attributes, if any
|
||||||
|
if (!(flags & print_no_indenting))
|
||||||
|
out = fill_chars(out, indent, Ch('\t'));
|
||||||
|
*out = Ch('<'), ++out;
|
||||||
|
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||||
|
out = print_attributes(out, node, flags);
|
||||||
|
|
||||||
|
// If node is childless
|
||||||
|
if (node->value_size() == 0 && !node->first_node())
|
||||||
|
{
|
||||||
|
// Print childless node tag ending
|
||||||
|
*out = Ch('/'), ++out;
|
||||||
|
*out = Ch('>'), ++out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Print normal node tag ending
|
||||||
|
*out = Ch('>'), ++out;
|
||||||
|
|
||||||
|
// Test if node contains a single data node only (and no other nodes)
|
||||||
|
xml_node<Ch> *child = node->first_node();
|
||||||
|
if (!child)
|
||||||
|
{
|
||||||
|
// If node has no children, only print its value without indenting
|
||||||
|
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||||
|
}
|
||||||
|
else if (child->next_sibling() == 0 && child->type() == node_data)
|
||||||
|
{
|
||||||
|
// If node has a sole data child, only print its value without indenting
|
||||||
|
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Print all children with full indenting
|
||||||
|
if (!(flags & print_no_indenting))
|
||||||
|
*out = Ch('\n'), ++out;
|
||||||
|
out = print_children(out, node, flags, indent + 1);
|
||||||
|
if (!(flags & print_no_indenting))
|
||||||
|
out = fill_chars(out, indent, Ch('\t'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print node end
|
||||||
|
*out = Ch('<'), ++out;
|
||||||
|
*out = Ch('/'), ++out;
|
||||||
|
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||||
|
*out = Ch('>'), ++out;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print declaration node
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||||
|
{
|
||||||
|
// Print declaration start
|
||||||
|
if (!(flags & print_no_indenting))
|
||||||
|
out = fill_chars(out, indent, Ch('\t'));
|
||||||
|
*out = Ch('<'), ++out;
|
||||||
|
*out = Ch('?'), ++out;
|
||||||
|
*out = Ch('x'), ++out;
|
||||||
|
*out = Ch('m'), ++out;
|
||||||
|
*out = Ch('l'), ++out;
|
||||||
|
|
||||||
|
// Print attributes
|
||||||
|
out = print_attributes(out, node, flags);
|
||||||
|
|
||||||
|
// Print declaration end
|
||||||
|
*out = Ch('?'), ++out;
|
||||||
|
*out = Ch('>'), ++out;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print comment node
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||||
|
{
|
||||||
|
assert(node->type() == node_comment);
|
||||||
|
if (!(flags & print_no_indenting))
|
||||||
|
out = fill_chars(out, indent, Ch('\t'));
|
||||||
|
*out = Ch('<'), ++out;
|
||||||
|
*out = Ch('!'), ++out;
|
||||||
|
*out = Ch('-'), ++out;
|
||||||
|
*out = Ch('-'), ++out;
|
||||||
|
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||||
|
*out = Ch('-'), ++out;
|
||||||
|
*out = Ch('-'), ++out;
|
||||||
|
*out = Ch('>'), ++out;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print doctype node
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||||
|
{
|
||||||
|
assert(node->type() == node_doctype);
|
||||||
|
if (!(flags & print_no_indenting))
|
||||||
|
out = fill_chars(out, indent, Ch('\t'));
|
||||||
|
*out = Ch('<'), ++out;
|
||||||
|
*out = Ch('!'), ++out;
|
||||||
|
*out = Ch('D'), ++out;
|
||||||
|
*out = Ch('O'), ++out;
|
||||||
|
*out = Ch('C'), ++out;
|
||||||
|
*out = Ch('T'), ++out;
|
||||||
|
*out = Ch('Y'), ++out;
|
||||||
|
*out = Ch('P'), ++out;
|
||||||
|
*out = Ch('E'), ++out;
|
||||||
|
*out = Ch(' '), ++out;
|
||||||
|
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||||
|
*out = Ch('>'), ++out;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print pi node
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||||
|
{
|
||||||
|
assert(node->type() == node_pi);
|
||||||
|
if (!(flags & print_no_indenting))
|
||||||
|
out = fill_chars(out, indent, Ch('\t'));
|
||||||
|
*out = Ch('<'), ++out;
|
||||||
|
*out = Ch('?'), ++out;
|
||||||
|
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||||
|
*out = Ch(' '), ++out;
|
||||||
|
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||||
|
*out = Ch('?'), ++out;
|
||||||
|
*out = Ch('>'), ++out;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//! \endcond
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Printing
|
||||||
|
|
||||||
|
//! Prints XML to given output iterator.
|
||||||
|
//! \param out Output iterator to print to.
|
||||||
|
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||||
|
//! \param flags Flags controlling how XML is printed.
|
||||||
|
//! \return Output iterator pointing to position immediately after last character of printed text.
|
||||||
|
template<class OutIt, class Ch>
|
||||||
|
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
|
||||||
|
{
|
||||||
|
return internal::print_node(out, &node, flags, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef RAPIDXML_NO_STREAMS
|
||||||
|
|
||||||
|
//! Prints XML to given output stream.
|
||||||
|
//! \param out Output stream to print to.
|
||||||
|
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||||
|
//! \param flags Flags controlling how XML is printed.
|
||||||
|
//! \return Output stream.
|
||||||
|
template<class Ch>
|
||||||
|
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
|
||||||
|
{
|
||||||
|
print(std::ostream_iterator<Ch>(out), node, flags);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
|
||||||
|
//! \param out Output stream to print to.
|
||||||
|
//! \param node Node to be printed.
|
||||||
|
//! \return Output stream.
|
||||||
|
template<class Ch>
|
||||||
|
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
|
||||||
|
{
|
||||||
|
return print(out, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
122
vendor/rapidxml-1.13/rapidxml_utils.hpp
vendored
Normal file
122
vendor/rapidxml-1.13/rapidxml_utils.hpp
vendored
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
|
||||||
|
#define RAPIDXML_UTILS_HPP_INCLUDED
|
||||||
|
|
||||||
|
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||||
|
// Version 1.13
|
||||||
|
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||||
|
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
|
||||||
|
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
|
||||||
|
|
||||||
|
#include "rapidxml.hpp"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace rapidxml
|
||||||
|
{
|
||||||
|
|
||||||
|
//! Represents data loaded from a file
|
||||||
|
template<class Ch = char>
|
||||||
|
class file
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! Loads file into the memory. Data will be automatically destroyed by the destructor.
|
||||||
|
//! \param filename Filename to load.
|
||||||
|
file(const char *filename)
|
||||||
|
{
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// Open stream
|
||||||
|
basic_ifstream<Ch> stream(filename, ios::binary);
|
||||||
|
if (!stream)
|
||||||
|
throw runtime_error(string("cannot open file ") + filename);
|
||||||
|
stream.unsetf(ios::skipws);
|
||||||
|
|
||||||
|
// Determine stream size
|
||||||
|
stream.seekg(0, ios::end);
|
||||||
|
size_t size = stream.tellg();
|
||||||
|
stream.seekg(0);
|
||||||
|
|
||||||
|
// Load data and add terminating 0
|
||||||
|
m_data.resize(size + 1);
|
||||||
|
stream.read(&m_data.front(), static_cast<streamsize>(size));
|
||||||
|
m_data[size] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Loads file into the memory. Data will be automatically destroyed by the destructor
|
||||||
|
//! \param stream Stream to load from
|
||||||
|
file(std::basic_istream<Ch> &stream)
|
||||||
|
{
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// Load data and add terminating 0
|
||||||
|
stream.unsetf(ios::skipws);
|
||||||
|
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
|
||||||
|
if (stream.fail() || stream.bad())
|
||||||
|
throw runtime_error("error reading stream");
|
||||||
|
m_data.push_back(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Gets file data.
|
||||||
|
//! \return Pointer to data of file.
|
||||||
|
Ch *data()
|
||||||
|
{
|
||||||
|
return &m_data.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Gets file data.
|
||||||
|
//! \return Pointer to data of file.
|
||||||
|
const Ch *data() const
|
||||||
|
{
|
||||||
|
return &m_data.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Gets file data size.
|
||||||
|
//! \return Size of file data, in characters.
|
||||||
|
std::size_t size() const
|
||||||
|
{
|
||||||
|
return m_data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::vector<Ch> m_data; // File data
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Counts children of node. Time complexity is O(n).
|
||||||
|
//! \return Number of children of node
|
||||||
|
template<class Ch>
|
||||||
|
inline std::size_t count_children(xml_node<Ch> *node)
|
||||||
|
{
|
||||||
|
xml_node<Ch> *child = node->first_node();
|
||||||
|
std::size_t count = 0;
|
||||||
|
while (child)
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
child = child->next_sibling();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Counts attributes of node. Time complexity is O(n).
|
||||||
|
//! \return Number of attributes of node
|
||||||
|
template<class Ch>
|
||||||
|
inline std::size_t count_attributes(xml_node<Ch> *node)
|
||||||
|
{
|
||||||
|
xml_attribute<Ch> *attr = node->first_attribute();
|
||||||
|
std::size_t count = 0;
|
||||||
|
while (attr)
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
attr = attr->next_attribute();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
1
vendor/skia
vendored
Submodule
1
vendor/skia
vendored
Submodule
Submodule vendor/skia added at c3ff0dfeae
Reference in New Issue
Block a user