webview-sys 0.4.1

Rust native ffi bindings for webview
Documentation
#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 <string.h>
#include <stdlib.h>
#include <stdio.h>

typedef void* webview_t;
typedef void (*webview_external_invoke_cb_t)(webview_t w, const char *arg);
typedef void (*webview_dispatch_fn)(webview_t w, void *arg);

enum webview_dialog_type {
  WEBVIEW_DIALOG_TYPE_OPEN = 0,
  WEBVIEW_DIALOG_TYPE_SAVE = 1,
  WEBVIEW_DIALOG_TYPE_ALERT = 2
};

WEBVIEW_API void webview_run(webview_t w);
WEBVIEW_API int webview_loop(webview_t w, int blocking);
WEBVIEW_API int webview_eval(webview_t w, const char *js);
WEBVIEW_API int webview_inject_css(webview_t w, const char *css);
WEBVIEW_API void webview_set_title(webview_t w, const char *title);
WEBVIEW_API void webview_set_fullscreen(webview_t w, int fullscreen);
WEBVIEW_API void webview_set_color(webview_t w, uint8_t r, uint8_t g,
                                   uint8_t b, uint8_t a);
WEBVIEW_API void webview_dialog(webview_t w,
                                enum webview_dialog_type dlgtype, int flags,
                                const char *title, const char *arg,
                                char *result, size_t resultsz);
WEBVIEW_API void webview_dispatch(webview_t w, webview_dispatch_fn fn,
                                  void *arg);
WEBVIEW_API void webview_exit(webview_t w);
WEBVIEW_API void webview_debug(const char *format, ...);
WEBVIEW_API void webview_print_log(const char *s);

WEBVIEW_API void* webview_get_user_data(webview_t w);
WEBVIEW_API webview_t webview_new(const char* title, const char* url, int width, int height, int resizable, int debug, int frameless, webview_external_invoke_cb_t external_invoke_cb, void* userdata);
WEBVIEW_API void webview_free(webview_t w);
WEBVIEW_API void webview_destroy(webview_t w);

// TODO WEBVIEW_API void webview_navigate(webview_t w, const char* url);

#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)


struct webview_dispatch_arg {
  webview_dispatch_fn fn;
  webview_t 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 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(webview_t 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;
}

static inline const char *webview_check_url(const char *url) {
  if (url == NULL || strlen(url) == 0) {
    return DEFAULT_URL;
  }
  return url;
}

// Convert ASCII hex digit to a nibble (four bits, 0 - 15).
//
// Use unsigned to avoid signed overflow UB.
static inline unsigned char hex2nibble(unsigned char c) {
  if (c >= '0' && c <= '9') {
    return c - '0';
  } else if (c >= 'a' && c <= 'f') {
    return 10 + (c - 'a');
  } else if (c >= 'A' && c <= 'F') {
    return 10 + (c - 'A');
  }
  return 0;
}

// Convert ASCII hex string (two characters) to byte.
//
// E.g., "0B" => 0x0B, "af" => 0xAF.
static inline char hex2char(const char* p) {
  return hex2nibble(p[0]) * 16 + hex2nibble(p[1]);
}

#ifdef __cplusplus
}
#endif

#endif // WEBVIEW_H