1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

//! Parsing stylesheets from bytes (not `&str`).

use crate::context::QuirksMode;
use crate::error_reporting::ParseErrorReporter;
use crate::media_queries::MediaList;
use crate::shared_lock::SharedRwLock;
use crate::stylesheets::{AllowImportRules, Origin, Stylesheet, StylesheetLoader, UrlExtraData};
use cssparser::{stylesheet_encoding, EncodingSupport};
use servo_arc::Arc;
use std::borrow::Cow;
use std::str;

struct EncodingRs;

impl EncodingSupport for EncodingRs {
    type Encoding = &'static encoding_rs::Encoding;

    fn utf8() -> Self::Encoding {
        encoding_rs::UTF_8
    }

    fn is_utf16_be_or_le(encoding: &Self::Encoding) -> bool {
        *encoding == encoding_rs::UTF_16LE || *encoding == encoding_rs::UTF_16BE
    }

    fn from_label(ascii_label: &[u8]) -> Option<Self::Encoding> {
        encoding_rs::Encoding::for_label(ascii_label)
    }
}

fn decode_stylesheet_bytes<'a>(
    css: &'a [u8],
    protocol_encoding_label: Option<&str>,
    environment_encoding: Option<&'static encoding_rs::Encoding>,
) -> Cow<'a, str> {
    let fallback_encoding = stylesheet_encoding::<EncodingRs>(
        css,
        protocol_encoding_label.map(str::as_bytes),
        environment_encoding,
    );
    let (result, _used_encoding, _) = fallback_encoding.decode(&css);
    // FIXME record used encoding for environment encoding of @import
    result
}

impl Stylesheet {
    /// Parse a stylesheet from a set of bytes, potentially received over the
    /// network.
    ///
    /// Takes care of decoding the network bytes and forwards the resulting
    /// string to `Stylesheet::from_str`.
    pub fn from_bytes(
        bytes: &[u8],
        url_data: UrlExtraData,
        protocol_encoding_label: Option<&str>,
        environment_encoding: Option<&'static encoding_rs::Encoding>,
        origin: Origin,
        media: MediaList,
        shared_lock: SharedRwLock,
        stylesheet_loader: Option<&dyn StylesheetLoader>,
        error_reporter: Option<&dyn ParseErrorReporter>,
        quirks_mode: QuirksMode,
    ) -> Stylesheet {
        let string = decode_stylesheet_bytes(bytes, protocol_encoding_label, environment_encoding);
        Stylesheet::from_str(
            &string,
            url_data,
            origin,
            Arc::new(shared_lock.wrap(media)),
            shared_lock,
            stylesheet_loader,
            error_reporter,
            quirks_mode,
            AllowImportRules::Yes,
        )
    }

    /// Updates an empty stylesheet with a set of bytes that reached over the
    /// network.
    pub fn update_from_bytes(
        existing: &Stylesheet,
        bytes: &[u8],
        protocol_encoding_label: Option<&str>,
        environment_encoding: Option<&'static encoding_rs::Encoding>,
        url_data: UrlExtraData,
        stylesheet_loader: Option<&dyn StylesheetLoader>,
        error_reporter: Option<&dyn ParseErrorReporter>,
    ) {
        let string = decode_stylesheet_bytes(bytes, protocol_encoding_label, environment_encoding);
        Self::update_from_str(
            existing,
            &string,
            url_data,
            stylesheet_loader,
            error_reporter,
            AllowImportRules::Yes,
        )
    }
}