text: /*
   * MIT License
   *
   * Copyright (c) 2017 Serge Zaitsev, (c) 2019 Quasar Framework
   *
   * 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.
   */
  #ifndef WEBVIEW_H
  #define WEBVIEW_H
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  #ifdef WEBVIEW_STATIC
  #define WEBVIEW_API static
  #else
  #define WEBVIEW_API extern
  #endif
  
  #include <stdint.h>
  #include <stdlib.h>
  #include <string.h>
  #include <stdarg.h>
  
  struct webview;
  
  typedef void (*webview_external_invoke_cb_t)(struct webview *w,
                                               const char *arg);
  
  struct webview {
    const char *url;
    const char *title;
    int width;
    int height;
    int resizable;
    int debug;
    webview_external_invoke_cb_t external_invoke_cb;
    struct webview_priv priv;
    void *userdata;
  };
  
  enum webview_dialog_type {
    WEBVIEW_DIALOG_TYPE_OPEN = 0,
    WEBVIEW_DIALOG_TYPE_SAVE = 1,
    WEBVIEW_DIALOG_TYPE_ALERT = 2
  };
  
  #define WEBVIEW_DIALOG_FLAG_FILE (0 << 0)
  #define WEBVIEW_DIALOG_FLAG_DIRECTORY (1 << 0)
  
  #define WEBVIEW_DIALOG_FLAG_INFO (1 << 1)
  #define WEBVIEW_DIALOG_FLAG_WARNING (2 << 1)
  #define WEBVIEW_DIALOG_FLAG_ERROR (3 << 1)
  #define WEBVIEW_DIALOG_FLAG_ALERT_MASK (3 << 1)
  
  typedef void (*webview_dispatch_fn)(struct webview *w, void *arg);
  
  struct webview_dispatch_arg {
    webview_dispatch_fn fn;
    struct webview *w;
    void *arg;
  };
  
  #define DEFAULT_URL                                                            \
    "data:text/"                                                                 \
    "html,%3C%21DOCTYPE%20html%3E%0A%3Chtml%20lang=%22en%22%3E%0A%3Chead%3E%"    \
    "3Cmeta%20charset=%22utf-8%22%3E%3Cmeta%20http-equiv=%22X-UA-Compatible%22%" \
    "20content=%22IE=edge%22%3E%3C%2Fhead%3E%0A%3Cbody%3E%3Cdiv%20id=%22app%22%" \
    "3E%3C%2Fdiv%3E%3Cscript%20type=%22text%2Fjavascript%22%3E%3C%2Fscript%3E%"  \
    "3C%2Fbody%3E%0A%3C%2Fhtml%3E"
  
  #define CSS_INJECT_FUNCTION                                                    \
    "(function(e){var "                                                          \
    "t=document.createElement('style'),d=document.head||document."               \
    "getElementsByTagName('head')[0];t.setAttribute('type','text/"               \
    "css'),t.styleSheet?t.styleSheet.cssText=e:t.appendChild(document."          \
    "createTextNode(e)),d.appendChild(t)})"
  
  static const char *webview_check_url(const char *url) {
    if (url == NULL || strlen(url) == 0) {
      return DEFAULT_URL;
    }
    return url;
  }
  
  WEBVIEW_API int webview(const char *title, const char *url, int width,
                          int height, int resizable);
  
  WEBVIEW_API int webview_init(struct webview *w);
  WEBVIEW_API int webview_loop(struct webview *w, int blocking);
  WEBVIEW_API int webview_eval(struct webview *w, const char *js);
  WEBVIEW_API int webview_inject_css(struct webview *w, const char *css);
  WEBVIEW_API void webview_set_title(struct webview *w, const char *title);
  WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen);
  WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
                                     uint8_t b, uint8_t a);
  WEBVIEW_API void webview_dialog(struct webview *w,
                                  enum webview_dialog_type dlgtype, int flags,
                                  const char *title, const char *arg,
                                  char *result, size_t resultsz);
  WEBVIEW_API void webview_dispatch(struct webview *w, webview_dispatch_fn fn,
                                    void *arg);
  WEBVIEW_API void webview_terminate(struct webview *w);
  WEBVIEW_API void webview_exit(struct webview *w);
  WEBVIEW_API void webview_debug(const char *format, ...);
  WEBVIEW_API void webview_print_log(const char *s);
  
  #ifdef WEBVIEW_IMPLEMENTATION
  #undef WEBVIEW_IMPLEMENTATION
  
  WEBVIEW_API int webview(const char *title, const char *url, int width,
                          int height, int resizable) {
    struct webview webview;
    memset(&webview, 0, sizeof(webview));
    webview.title = title;
    webview.url = url;
    webview.width = width;
    webview.height = height;
    webview.resizable = resizable;
    int r = webview_init(&webview);
    if (r != 0) {
      return r;
    }
    while (webview_loop(&webview, 1) == 0) {
    }
    webview_exit(&webview);
    return 0;
  }
  
  WEBVIEW_API void webview_debug(const char *format, ...) {
    char buf[4096];
    va_list ap;
    va_start(ap, format);
    vsnprintf(buf, sizeof(buf), format, ap);
    webview_print_log(buf);
    va_end(ap);
  }
  
  static int webview_js_encode(const char *s, char *esc, size_t n) {
    int r = 1; /* At least one byte for trailing zero */
    for (; *s; s++) {
      const unsigned char c = *s;
      if (c >= 0x20 && c < 0x80 && strchr("<>\\'\"", c) == NULL) {
        if (n > 0) {
          *esc++ = c;
          n--;
        }
        r++;
      } else {
        if (n > 0) {
          snprintf(esc, n, "\\x%02x", (int)c);
          esc += 4;
          n -= 4;
        }
        r += 4;
      }
    }
    return r;
  }
  
  WEBVIEW_API int webview_inject_css(struct webview *w, const char *css) {
    int n = webview_js_encode(css, NULL, 0);
    char *esc = (char *)calloc(1, sizeof(CSS_INJECT_FUNCTION) + n + 4);
    if (esc == NULL) {
      return -1;
    }
    char *js = (char *)calloc(1, n);
    webview_js_encode(css, js, n);
    snprintf(esc, sizeof(CSS_INJECT_FUNCTION) + n + 4, "%s(\"%s\")",
             CSS_INJECT_FUNCTION, js);
    int r = webview_eval(w, esc);
    free(js);
    free(esc);
    return r;
  }
  
  #endif /* WEBVIEW_IMPLEMENTATION */
  
  #ifdef __cplusplus
  }
  #endif
  
  #endif /* WEBVIEW_H */
  