void HTMLStyleElementImp::handleMutation(EventListenerImp* listener, events::Event event)
{
    // TODO: update type, media, and scoped. Then check type.

    events::MutationEvent mutation(interface_cast<events::MutationEvent>(event));

    DocumentImp* document = getOwnerDocumentImp();
    if (!document)
        return;

    if (mutation.getType() == u"DOMNodeRemoved" && event.getTarget().self() == this)
        styleSheet = 0;
    else {
        std::u16string content;
        for (Node node = getFirstChild(); node; node = node.getNextSibling()) {
            if (TextImp* text = dynamic_cast<TextImp*>(node.self()))  // TODO better to avoid imp call?
                content += text->getData();
        }
        CSSParser parser;
        styleSheet = parser.parse(document, content);
        if (auto imp = dynamic_cast<CSSStyleSheetImp*>(styleSheet.self())) {
            imp->setOwnerNode(this);
            if (4 <= getLogLevel())
                dumpStyleSheet(std::cerr, imp);
        }
    }
    if (WindowImp* view = document->getDefaultWindow())
        view->setFlags(Box::NEED_SELECTOR_REMATCHING);
    document->resetStyleSheets();
}
css::CSSStyleSheet loadStyleSheet(const char* path)
{
    char url[PATH_MAX + 7];
    strcpy(url, "file://");
    realpath(path, url + 7);
    std::ifstream stream(path);
    if (!stream) {
        std::cerr << "error: cannot open " << path << ".\n";
        exit(EXIT_FAILURE);
    }
    CSSParser parser;
    CSSInputStream cssStream(stream, "utf-8");
    css::CSSStyleSheet sheet = parser.parse(0, cssStream);
    if (auto imp = dynamic_cast<CSSStyleSheetImp*>(sheet.self()))
        imp->setHref(toString(url));
    return sheet;
}
css::CSSStyleSheet loadStyleSheet(std::istream& stream)
{
    CSSParser parser;
    CSSInputStream cssStream(stream, "utf-8");
    return parser.parse(0, cssStream);
}