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
104
105
106
107
108
109
// Copyright (c) 2014 Richard Diamond & contributors.
//
// This file is part of the Rust PPApi project.
//
// 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 http://mozilla.org/MPL/2.0/.

use libc::c_void;
use std::ops;

use super::ffi;
use super::{Resource};
use super::ppb;
use ppb::ImageDataIf;

#[derive(Hash, Eq, PartialEq, Show)] pub struct ImageData(ffi::PP_Resource);

impl_resource_for!(ImageData, ResourceType::ImageDataRes);

#[derive(Eq, PartialEq, Hash, Clone, Copy)]
pub enum Format {
    BGRA = ffi::PP_IMAGEDATAFORMAT_BGRA_PREMUL as int,
    RGBA = ffi::PP_IMAGEDATAFORMAT_RGBA_PREMUL as int,
}
impl Format {
    fn from_ffi(v: ffi::PP_ImageDataFormat) -> Format {
        match v {
            ffi::PP_IMAGEDATAFORMAT_BGRA_PREMUL => Format::BGRA,
            ffi::PP_IMAGEDATAFORMAT_RGBA_PREMUL => Format::RGBA,
            _ => panic!(),
        }
    }
    pub fn to_ffi(&self) -> ffi::PP_ImageDataFormat {
        match *self {
            Format::BGRA => ffi::PP_IMAGEDATAFORMAT_BGRA_PREMUL,
            Format::RGBA => ffi::PP_IMAGEDATAFORMAT_RGBA_PREMUL,
        }
    }
    pub fn is_supported(&self) -> bool {
        let ffi_val = *self as ffi::PP_ImageDataFormat;
        (ppb::get_image_data().IsImageDataFormatSupported.unwrap())(ffi_val) != 0
    }
}

#[derive(Clone, Copy)]
pub struct Description {
    pub format: Format,
    pub size: super::Size,

    /** Taken from the Google PPAPI docs
     * This value represents the row width in bytes. This may be different than
     * width * 4 since there may be padding at the end of the lines.
     */
    pub line_stride: u32,
}
impl Description {
    pub fn from_ffi(desc: ffi::Struct_PP_ImageDataDesc) -> Description {
        use core::mem::transmute;
        Description {
            format: Format::from_ffi(desc.format),
            size:   unsafe { transmute(desc.size) },
            line_stride: desc.stride as u32,
        }
    }
}

pub struct MappedImage<'a> {
    img: &'a ImageData,
    pub desc: Description,
    ptr: *mut c_void,
}
pub trait MappedSlice<'a> {
    fn as_imm_slice(&self) -> &'a [u8];
}
impl<'a> MappedSlice<'a> for MappedImage<'a> {
    fn as_imm_slice(&self) -> &'a [u8] {
        use std::slice::from_raw_buf;
        use std::mem::transmute;
        let size = (self.desc.size.height * self.desc.line_stride) as usize;

        unsafe { from_raw_buf(transmute(&self.ptr), size) }
    }
}
#[unsafe_destructor]
impl<'a> ops::Drop for MappedImage<'a> {
    fn drop(&mut self) {
        ppb::get_image_data().unmap(&self.img.unwrap());
    }
}

pub fn native_image_data_format() -> Format {
    Format::from_ffi(ppb::get_image_data().native_image_data_format())
}

impl ImageData {
    pub fn describe(&self) -> Option<Description> {
        ppb::get_image_data()
            .describe(self.unwrap())
            .map(|desc| Description::from_ffi(desc) )
    }
    pub fn map<'a>(&'a self) -> MappedImage<'a> {
        MappedImage {
            img: self,
            desc: self.describe().unwrap(),
            ptr: ppb::get_image_data().map(&self.unwrap()),
        }
    }
}