1/*
2 * Copyright (C) 2014 Igalia S.L.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB.  If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "WebKitUserContent.h"
22
23#include "WebKitPrivate.h"
24#include "WebKitUserContentPrivate.h"
25#include <wtf/text/CString.h>
26#include <wtf/text/StringBuilder.h>
27
28using namespace WebCore;
29
30/**
31 * SECTION:WebKitUserContent
32 * @short_description: Defines user content types which affect web pages.
33 * @title: User content
34 *
35 * See also: #WebKitUserContentManager
36 *
37 * Since: 2.6
38 */
39
40static inline UserContentInjectedFrames toUserContentInjectedFrames(WebKitUserContentInjectedFrames injectedFrames)
41{
42    switch (injectedFrames) {
43    case WEBKIT_USER_CONTENT_INJECT_TOP_FRAME:
44        return InjectInTopFrameOnly;
45    case WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES:
46        return InjectInAllFrames;
47    default:
48        ASSERT_NOT_REACHED();
49        return InjectInAllFrames;
50    }
51}
52
53static inline UserStyleLevel toUserStyleLevel(WebKitUserStyleLevel styleLevel)
54{
55    switch (styleLevel) {
56    case WEBKIT_USER_STYLE_LEVEL_USER:
57        return UserStyleUserLevel;
58    case WEBKIT_USER_STYLE_LEVEL_AUTHOR:
59        return UserStyleAuthorLevel;
60    default:
61        ASSERT_NOT_REACHED();
62        return UserStyleAuthorLevel;
63    }
64}
65
66static inline Vector<String> toStringVector(const char* const* strv)
67{
68    if (!strv)
69        return Vector<String>();
70
71    Vector<String> result;
72    for (auto str = strv; *str; ++str)
73        result.append(std::move(String::fromUTF8(*str)));
74    return result;
75}
76
77struct _WebKitUserStyleSheet {
78    _WebKitUserStyleSheet(const gchar* source, WebKitUserContentInjectedFrames injectedFrames, WebKitUserStyleLevel level, const char* const* whitelist, const char* const* blacklist)
79        : userStyleSheet(std::make_unique<UserStyleSheet>(
80            String::fromUTF8(source), URL { },
81            toStringVector(whitelist), toStringVector(blacklist),
82            toUserContentInjectedFrames(injectedFrames),
83            toUserStyleLevel(level)))
84        , referenceCount(1)
85    {
86    }
87
88    std::unique_ptr<UserStyleSheet> userStyleSheet;
89    int referenceCount;
90};
91
92G_DEFINE_BOXED_TYPE(WebKitUserStyleSheet, webkit_user_style_sheet, webkit_user_style_sheet_ref, webkit_user_style_sheet_unref)
93
94/**
95 * webkit_user_style_sheet_ref:
96 * @user_style_sheet: a #WebKitUserStyleSheet
97 *
98 * Atomically increments the reference count of @user_style_sheet by one.
99 * This function is MT-safe and may be called from any thread.
100 *
101 * Returns: The passed #WebKitUserStyleSheet
102 *
103 * Since: 2.6
104 */
105WebKitUserStyleSheet* webkit_user_style_sheet_ref(WebKitUserStyleSheet* userStyleSheet)
106{
107    g_atomic_int_inc(&userStyleSheet->referenceCount);
108    return userStyleSheet;
109}
110
111/**
112 * webkit_user_style_sheet_unref:
113 * @user_style_sheet: a #WebKitUserStyleSheet
114 *
115 * Atomically decrements the reference count of @user_style_sheet by one.
116 * If the reference count drops to 0, all memory allocated by
117 * #WebKitUserStyleSheet is released. This function is MT-safe and may be
118 * called from any thread.
119 *
120 * Since: 2.6
121 */
122void webkit_user_style_sheet_unref(WebKitUserStyleSheet* userStyleSheet)
123{
124    if (g_atomic_int_dec_and_test(&userStyleSheet->referenceCount)) {
125        userStyleSheet->~WebKitUserStyleSheet();
126        g_slice_free(WebKitUserStyleSheet, userStyleSheet);
127    }
128}
129
130/**
131 * webkit_user_style_sheet_new:
132 * @source: Source code of the user style sheet.
133 * @injected_frames: A #WebKitUserContentInjectedFrames value
134 * @level: A #WebKitUserStyleLevel
135 * @whitelist: (array zero-terminated=1) (allow-none): A whitelist of URI patterns or %NULL
136 * @blacklist: (array zero-terminated=1) (allow-none): A blacklist of URI patterns or %NULL
137 *
138 * Creates a new user style sheet. Style sheets can be applied to some URIs
139 * only by passing non-null values for @whitelist or @blacklist. Passing a
140 * %NULL whitelist implies that all URIs are on the whitelist. The style
141 * sheet is applied if an URI matches the whitelist and not the blacklist.
142 * URI patterns must be of the form `[protocol]://[host]/[path]`, where the
143 * *host* and *path* components can contain the wildcard character (`*`) to
144 * represent zero or more other characters.
145 *
146 * Returns: A new #WebKitUserStyleSheet
147 *
148 * Since: 2.6
149 */
150WebKitUserStyleSheet* webkit_user_style_sheet_new(const gchar* source, WebKitUserContentInjectedFrames injectedFrames, WebKitUserStyleLevel level, const char* const* whitelist, const char* const* blacklist)
151{
152    g_return_val_if_fail(source, nullptr);
153    WebKitUserStyleSheet* userStyleSheet = g_slice_new(WebKitUserStyleSheet);
154    new (userStyleSheet) WebKitUserStyleSheet(source, injectedFrames, level, whitelist, blacklist);
155    return userStyleSheet;
156}
157
158const UserStyleSheet& webkitUserStyleSheetGetUserStyleSheet(WebKitUserStyleSheet* userStyleSheet)
159{
160    return *userStyleSheet->userStyleSheet;
161}
162