From 92ce50b7fb8d303c54647f771df89e5c082c137c Mon Sep 17 00:00:00 2001 From: Yuri Kobets Date: Tue, 13 Jun 2023 00:36:18 +0300 Subject: [PATCH] refactor render_item based classes All render_item based classes are moved into the own headers --- CMakeLists.txt | 8 +- include/litehtml/render_block.h | 40 ++++ include/litehtml/render_block_context.h | 29 +++ include/litehtml/render_flex.h | 46 +++++ include/litehtml/render_image.h | 25 +++ include/litehtml/render_inline.h | 30 +++ include/litehtml/render_inline_context.h | 55 ++++++ include/litehtml/render_item.h | 222 +---------------------- include/litehtml/render_table.h | 56 ++++++ src/document.cpp | 2 + src/el_image.cpp | 2 +- src/element.cpp | 3 + src/render_block.cpp | 4 +- src/render_block_context.cpp | 2 +- src/render_flex.cpp | 2 +- src/render_image.cpp | 2 +- src/render_inline.cpp | 3 - src/render_inline_context.cpp | 2 +- src/render_item.cpp | 18 -- src/render_table.cpp | 20 +- 20 files changed, 321 insertions(+), 250 deletions(-) create mode 100644 include/litehtml/render_block.h create mode 100644 include/litehtml/render_block_context.h create mode 100644 include/litehtml/render_flex.h create mode 100644 include/litehtml/render_image.h create mode 100644 include/litehtml/render_inline.h create mode 100644 include/litehtml/render_inline_context.h create mode 100644 include/litehtml/render_table.h delete mode 100644 src/render_inline.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 014089023..58a598881 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,6 @@ set(SOURCE_LITEHTML src/render_block_context.cpp src/render_block.cpp src/render_inline_context.cpp - src/render_inline.cpp src/render_table.cpp src/render_flex.cpp src/render_image.cpp @@ -123,6 +122,13 @@ set(HEADER_LITEHTML include/litehtml/css_properties.h include/litehtml/line_box.h include/litehtml/render_item.h + include/litehtml/render_flex.h + include/litehtml/render_image.h + include/litehtml/render_inline.h + include/litehtml/render_table.h + include/litehtml/render_inline_context.h + include/litehtml/render_block_context.h + include/litehtml/render_block.h include/litehtml/master_css.h include/litehtml/string_id.h include/litehtml/formatting_context.h diff --git a/include/litehtml/render_block.h b/include/litehtml/render_block.h new file mode 100644 index 000000000..eb058c618 --- /dev/null +++ b/include/litehtml/render_block.h @@ -0,0 +1,40 @@ +#ifndef LITEHTML_RENDER_BLOCK_H +#define LITEHTML_RENDER_BLOCK_H + +#include "render_item.h" + +namespace litehtml +{ + class render_item_block : public render_item + { + protected: + /** + * Render block content. + * + * @param x - horizontal position of the content + * @param y - vertical position of the content + * @param second_pass - true is this is the second pass. + * @param ret_width - input minimal width. + * @param self_size - defines calculated size of block + * @return return value is the minimal width of the content in block. Must be greater or equal to ret_width parameter + */ + virtual int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) {return 0;} + int _render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) override; + int place_float(const std::shared_ptr &el, int top, const containing_block_context &self_size, formatting_context* fmt_ctx); + virtual void fix_line_width(element_float flt, + const containing_block_context &containing_block_size, formatting_context* fmt_ctx) + {} + + public: + explicit render_item_block(std::shared_ptr src_el) : render_item(std::move(src_el)) + {} + + std::shared_ptr clone() override + { + return std::make_shared(src_el()); + } + std::shared_ptr init() override; + }; +} + +#endif //LITEHTML_RENDER_BLOCK_H diff --git a/include/litehtml/render_block_context.h b/include/litehtml/render_block_context.h new file mode 100644 index 000000000..3b5192261 --- /dev/null +++ b/include/litehtml/render_block_context.h @@ -0,0 +1,29 @@ +#ifndef LITEHTML_RENDER_BLOCK_CONTEXT_H +#define LITEHTML_RENDER_BLOCK_CONTEXT_H + +#include "render_block.h" + +namespace litehtml +{ + /** + * In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a + * containing block. + * https://www.w3.org/TR/CSS22/visuren.html#block-formatting + */ + class render_item_block_context : public render_item_block + { + protected: + int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override; + + public: + explicit render_item_block_context(std::shared_ptr src_el) : render_item_block(std::move(src_el)) + {} + + std::shared_ptr clone() override + { + return std::make_shared(src_el()); + } + }; +} + +#endif //LITEHTML_RENDER_BLOCK_CONTEXT_H diff --git a/include/litehtml/render_flex.h b/include/litehtml/render_flex.h new file mode 100644 index 000000000..5d31bc9bf --- /dev/null +++ b/include/litehtml/render_flex.h @@ -0,0 +1,46 @@ +#ifndef LITEHTML_RENDER_FLEX_H +#define LITEHTML_RENDER_FLEX_H + +#include "render_block.h" + +namespace litehtml +{ + class render_item_flex : public render_item_block + { + struct flex_item + { + std::shared_ptr el; + int base_size; + int main_size; + int min_width; + int max_width; + int line; + + explicit flex_item(std::shared_ptr _el) : + el(std::move(_el)), + min_width(0), + max_width(0), + line(0), + base_size(0), + main_size(0) + {} + }; + protected: + std::list> m_flex_items; + + int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override; + + public: + explicit render_item_flex(std::shared_ptr src_el) : render_item_block(std::move(src_el)) + {} + + std::shared_ptr clone() override + { + return std::make_shared(src_el()); + } + void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override; + std::shared_ptr init() override; + }; +} + +#endif //LITEHTML_RENDER_FLEX_H diff --git a/include/litehtml/render_image.h b/include/litehtml/render_image.h new file mode 100644 index 000000000..e85f487ca --- /dev/null +++ b/include/litehtml/render_image.h @@ -0,0 +1,25 @@ +#ifndef LITEHTML_RENDER_IMAGE_H +#define LITEHTML_RENDER_IMAGE_H + +#include "render_item.h" + +namespace litehtml +{ + class render_item_image : public render_item + { + protected: + int calc_max_height(int image_height, int containing_block_height); + int _render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) override; + + public: + explicit render_item_image(std::shared_ptr src_el) : render_item(std::move(src_el)) + {} + + std::shared_ptr clone() override + { + return std::make_shared(src_el()); + } + }; +} + +#endif //LITEHTML_RENDER_IMAGE_H diff --git a/include/litehtml/render_inline.h b/include/litehtml/render_inline.h new file mode 100644 index 000000000..476011563 --- /dev/null +++ b/include/litehtml/render_inline.h @@ -0,0 +1,30 @@ +#ifndef LITEHTML_RENDER_INLINE_H +#define LITEHTML_RENDER_INLINE_H + +#include "render_item.h" + +namespace litehtml +{ + class render_item_inline : public render_item + { + protected: + position::vector m_boxes; + + public: + explicit render_item_inline(std::shared_ptr src_el) : render_item(std::move(src_el)) + {} + + void get_inline_boxes( position::vector& boxes ) const override { boxes = m_boxes; } + void set_inline_boxes( position::vector& boxes ) override { m_boxes = boxes; } + void add_inline_box( const position& box ) override { m_boxes.emplace_back(box); }; + void clear_inline_boxes() override { m_boxes.clear(); } + int get_base_line() override { return src_el()->css().get_font_metrics().base_line(); } + + std::shared_ptr clone() override + { + return std::make_shared(src_el()); + } + }; +} + +#endif //LITEHTML_RENDER_INLINE_H diff --git a/include/litehtml/render_inline_context.h b/include/litehtml/render_inline_context.h new file mode 100644 index 000000000..894cfe989 --- /dev/null +++ b/include/litehtml/render_inline_context.h @@ -0,0 +1,55 @@ +#ifndef LITEHTML_RENDER_INLINE_CONTEXT_H +#define LITEHTML_RENDER_INLINE_CONTEXT_H + +#include "render_block.h" + +namespace litehtml +{ + /** + * An inline formatting context is established by a block container box that contains no block-level boxes. + * https://www.w3.org/TR/CSS22/visuren.html#inline-formatting + */ + class render_item_inline_context : public render_item_block + { + /** + * Structure contains elements with display: inline + * members: + * - element: render_item with display: inline + * - boxes: rectangles represented inline element content. There are can be many boxes if content + * is split into some lines + * - start_box: the start position of currently calculated box + */ + struct inlines_item + { + std::shared_ptr element; + position::vector boxes; + position start_box; + + explicit inlines_item(const std::shared_ptr& el) : element(el) {} + }; + protected: + std::vector > m_line_boxes; + int m_max_line_width; + + int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override; + void fix_line_width(element_float flt, + const containing_block_context &self_size, formatting_context* fmt_ctx) override; + + std::list > finish_last_box(bool end_of_render, const containing_block_context &self_size); + void place_inline(std::unique_ptr item, const containing_block_context &self_size, formatting_context* fmt_ctx); + int new_box(const std::unique_ptr& el, line_context& line_ctx, const containing_block_context &self_size, formatting_context* fmt_ctx); + void apply_vertical_align() override; + public: + explicit render_item_inline_context(std::shared_ptr src_el) : render_item_block(std::move(src_el)), m_max_line_width(0) + {} + + std::shared_ptr clone() override + { + return std::make_shared(src_el()); + } + + int get_base_line() override; + }; +} + +#endif //LITEHTML_RENDER_INLINE_CONTEXT_H diff --git a/include/litehtml/render_item.h b/include/litehtml/render_item.h index db2cf1255..9d4561e5a 100644 --- a/include/litehtml/render_item.h +++ b/include/litehtml/render_item.h @@ -273,8 +273,6 @@ namespace litehtml ri->parent(shared_from_this()); } - int render(int x, int y, const containing_block_context& containing_block_size, formatting_context* fmt_ctx, bool second_pass = false); - bool is_root() const { return m_parent.expired(); @@ -305,6 +303,7 @@ namespace litehtml return !(m_skip || src_el()->css().get_display() == display_none || src_el()->css().get_visibility() != visibility_visible); } + int render(int x, int y, const containing_block_context& containing_block_size, formatting_context* fmt_ctx, bool second_pass = false); int calc_width(int defVal, int containing_block_width) const; bool get_predefined_height(int& p_height, int containing_block_height) const; void apply_relative_shift(const containing_block_context &containing_block_size); @@ -348,225 +347,6 @@ namespace litehtml */ void get_rendering_boxes( position::vector& redraw_boxes); }; - - class render_item_block : public render_item - { - protected: - /** - * Render block content. - * - * @param x - horizontal position of the content - * @param y - vertical position of the content - * @param second_pass - true is this is the second pass. - * @param ret_width - input minimal width. - * @param self_size - defines calculated size of block - * @return return value is the minimal width of the content in block. Must be greater or equal to ret_width parameter - */ - virtual int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) {return 0;} - int _render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) override; - int place_float(const std::shared_ptr &el, int top, const containing_block_context &self_size, formatting_context* fmt_ctx); - virtual void fix_line_width(element_float flt, - const containing_block_context &containing_block_size, formatting_context* fmt_ctx) - {} - - public: - explicit render_item_block(std::shared_ptr src_el) : render_item(std::move(src_el)) - {} - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - std::shared_ptr init() override; - }; - - /** - * In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a - * containing block. - * https://www.w3.org/TR/CSS22/visuren.html#block-formatting - */ - class render_item_block_context : public render_item_block - { - protected: - int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override; - - public: - explicit render_item_block_context(std::shared_ptr src_el) : render_item_block(std::move(src_el)) - {} - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - }; - - /** - * An inline formatting context is established by a block container box that contains no block-level boxes. - * https://www.w3.org/TR/CSS22/visuren.html#inline-formatting - */ - class render_item_inline_context : public render_item_block - { - /** - * Structure contains elements with display: inline - * members: - * - element: render_item with display: inline - * - boxes: rectangles represented inline element content. There are can be many boxes if content - * is split into some lines - * - start_box: the start position of currently calculated box - */ - struct inlines_item - { - std::shared_ptr element; - position::vector boxes; - position start_box; - - explicit inlines_item(const std::shared_ptr& el) : element(el) {} - }; - protected: - std::vector > m_line_boxes; - int m_max_line_width; - - int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override; - void fix_line_width(element_float flt, - const containing_block_context &self_size, formatting_context* fmt_ctx) override; - - std::list > finish_last_box(bool end_of_render, const containing_block_context &self_size); - void place_inline(std::unique_ptr item, const containing_block_context &self_size, formatting_context* fmt_ctx); - int new_box(const std::unique_ptr& el, line_context& line_ctx, const containing_block_context &self_size, formatting_context* fmt_ctx); - void apply_vertical_align() override; - public: - explicit render_item_inline_context(std::shared_ptr src_el) : render_item_block(std::move(src_el)), m_max_line_width(0) - {} - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - - int get_base_line() override; - }; - - class render_item_table : public render_item - { - protected: - // data for table rendering - std::unique_ptr m_grid; - int m_border_spacing_x; - int m_border_spacing_y; - - int _render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) override; - - public: - explicit render_item_table(std::shared_ptr src_el); - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override; - int get_draw_vertical_offset() override; - std::shared_ptr init() override; - }; - - class render_item_table_part : public render_item - { - public: - explicit render_item_table_part(std::shared_ptr src_el) : render_item(std::move(src_el)) - {} - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - }; - - class render_item_table_row : public render_item - { - public: - explicit render_item_table_row(std::shared_ptr src_el) : render_item(std::move(src_el)) - {} - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - void get_inline_boxes( position::vector& boxes ) const override; - }; - - class render_item_inline : public render_item - { - protected: - position::vector m_boxes; - - public: - explicit render_item_inline(std::shared_ptr src_el) : render_item(std::move(src_el)) - {} - - void get_inline_boxes( position::vector& boxes ) const override { boxes = m_boxes; } - void set_inline_boxes( position::vector& boxes ) override { m_boxes = boxes; } - void add_inline_box( const position& box ) override { m_boxes.emplace_back(box); }; - void clear_inline_boxes() override { m_boxes.clear(); } - int get_base_line() override { return src_el()->css().get_font_metrics().base_line(); } - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - }; - - class render_item_image : public render_item - { - protected: - int calc_max_height(int image_height, int containing_block_height); - int _render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) override; - - public: - explicit render_item_image(std::shared_ptr src_el) : render_item(std::move(src_el)) - {} - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - }; - - class render_item_flex : public render_item_block - { - struct flex_item - { - std::shared_ptr el; - int base_size; - int main_size; - int min_width; - int max_width; - int line; - - explicit flex_item(std::shared_ptr _el) : - el(std::move(_el)), - min_width(0), - max_width(0), - line(0), - base_size(0), - main_size(0) - {} - }; - protected: - std::list> m_flex_items; - - int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override; - - public: - explicit render_item_flex(std::shared_ptr src_el) : render_item_block(std::move(src_el)) - {} - - std::shared_ptr clone() override - { - return std::make_shared(src_el()); - } - void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override; - std::shared_ptr init() override; - }; - } #endif //LH_RENDER_ITEM_H diff --git a/include/litehtml/render_table.h b/include/litehtml/render_table.h new file mode 100644 index 000000000..57fe435df --- /dev/null +++ b/include/litehtml/render_table.h @@ -0,0 +1,56 @@ +#ifndef LITEHTML_RENDER_TABLE_H +#define LITEHTML_RENDER_TABLE_H + +#include "render_item.h" + +namespace litehtml +{ + class render_item_table : public render_item + { + protected: + // data for table rendering + std::unique_ptr m_grid; + int m_border_spacing_x; + int m_border_spacing_y; + + int _render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) override; + + public: + explicit render_item_table(std::shared_ptr src_el); + + std::shared_ptr clone() override + { + return std::make_shared(src_el()); + } + void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override; + int get_draw_vertical_offset() override; + std::shared_ptr init() override; + }; + + class render_item_table_part : public render_item + { + public: + explicit render_item_table_part(std::shared_ptr src_el) : render_item(std::move(src_el)) + {} + + std::shared_ptr clone() override + { + return std::make_shared(src_el()); + } + }; + + class render_item_table_row : public render_item + { + public: + explicit render_item_table_row(std::shared_ptr src_el) : render_item(std::move(src_el)) + {} + + std::shared_ptr clone() override + { + return std::make_shared(src_el()); + } + void get_inline_boxes( position::vector& boxes ) const override; + }; +} + +#endif //LITEHTML_RENDER_TABLE_H diff --git a/src/document.cpp b/src/document.cpp index 4ba36b4ea..ec336613d 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -27,6 +27,8 @@ #include "gumbo.h" #include "utf8_strings.h" #include "render_item.h" +#include "render_table.h" +#include "render_block.h" litehtml::document::document(document_container* objContainer) { diff --git a/src/el_image.cpp b/src/el_image.cpp index 34b8a7aef..9cf8146b4 100644 --- a/src/el_image.cpp +++ b/src/el_image.cpp @@ -1,6 +1,6 @@ #include "html.h" #include "el_image.h" -#include "render_item.h" +#include "render_image.h" litehtml::el_image::el_image(const document::ptr& doc) : html_tag(doc) { diff --git a/src/element.cpp b/src/element.cpp index 234e95975..1d0a509b1 100644 --- a/src/element.cpp +++ b/src/element.cpp @@ -2,6 +2,9 @@ #include "element.h" #include "document.h" #include "render_item.h" +#include "render_flex.h" +#include "render_inline.h" +#include "render_table.h" #include "el_before_after.h" namespace litehtml diff --git a/src/render_block.cpp b/src/render_block.cpp index a9568d11e..d653f3114 100644 --- a/src/render_block.cpp +++ b/src/render_block.cpp @@ -1,5 +1,7 @@ #include "html.h" -#include "render_item.h" +#include "render_block.h" +#include "render_inline_context.h" +#include "render_block_context.h" #include "document.h" int litehtml::render_item_block::place_float(const std::shared_ptr &el, int top, const containing_block_context &self_size, formatting_context* fmt_ctx) diff --git a/src/render_block_context.cpp b/src/render_block_context.cpp index 0d16ab58f..7591378c2 100644 --- a/src/render_block_context.cpp +++ b/src/render_block_context.cpp @@ -1,5 +1,5 @@ #include "html.h" -#include "render_item.h" +#include "render_block_context.h" #include "document.h" int litehtml::render_item_block_context::_render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) diff --git a/src/render_flex.cpp b/src/render_flex.cpp index 983f61812..2cab59e04 100644 --- a/src/render_flex.cpp +++ b/src/render_flex.cpp @@ -1,6 +1,6 @@ #include "html.h" -#include "render_item.h" #include "types.h" +#include "render_flex.h" int litehtml::render_item_flex::_render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) { diff --git a/src/render_image.cpp b/src/render_image.cpp index 37105278e..63e622d7b 100644 --- a/src/render_image.cpp +++ b/src/render_image.cpp @@ -1,5 +1,5 @@ #include "html.h" -#include "render_item.h" +#include "render_image.h" #include "document.h" int litehtml::render_item_image::_render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) diff --git a/src/render_inline.cpp b/src/render_inline.cpp deleted file mode 100644 index 0ea24b17d..000000000 --- a/src/render_inline.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "html.h" -#include "render_item.h" - diff --git a/src/render_inline_context.cpp b/src/render_inline_context.cpp index 72cd1fe3d..2d8f2e173 100644 --- a/src/render_inline_context.cpp +++ b/src/render_inline_context.cpp @@ -1,5 +1,5 @@ #include "html.h" -#include "render_item.h" +#include "render_inline_context.h" #include "document.h" #include "iterators.h" diff --git a/src/render_item.cpp b/src/render_item.cpp index 808ffaf3f..4eb25757d 100644 --- a/src/render_item.cpp +++ b/src/render_item.cpp @@ -1086,21 +1086,3 @@ litehtml::containing_block_context litehtml::render_item::calculate_containing_b } return ret; } - -void litehtml::render_item_table_row::get_inline_boxes( position::vector& boxes ) const -{ - position pos; - for(auto& el : m_children) - { - if(el->src_el()->css().get_display() == display_table_cell) - { - pos.x = el->left() + el->margin_left(); - pos.y = el->top() - m_padding.top - m_borders.top; - - pos.width = el->right() - pos.x - el->margin_right() - el->margin_left(); - pos.height = el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom; - - boxes.push_back(pos); - } - } -} diff --git a/src/render_table.cpp b/src/render_table.cpp index c6756304e..3720bfcd0 100644 --- a/src/render_table.cpp +++ b/src/render_table.cpp @@ -1,5 +1,5 @@ #include "html.h" -#include "render_item.h" +#include "render_table.h" #include "document.h" #include "iterators.h" @@ -462,3 +462,21 @@ int litehtml::render_item_table::get_draw_vertical_offset() } return 0; } + +void litehtml::render_item_table_row::get_inline_boxes( position::vector& boxes ) const +{ + position pos; + for(auto& el : m_children) + { + if(el->src_el()->css().get_display() == display_table_cell) + { + pos.x = el->left() + el->margin_left(); + pos.y = el->top() - m_padding.top - m_borders.top; + + pos.width = el->right() - pos.x - el->margin_right() - el->margin_left(); + pos.height = el->height() + m_padding.top + m_padding.bottom + m_borders.top + m_borders.bottom; + + boxes.push_back(pos); + } + } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy