diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj
index 9f412a2ce..c98199ee1 100644
--- a/CrossPlatformModules.csproj
+++ b/CrossPlatformModules.csproj
@@ -241,6 +241,7 @@
image-source.d.ts
+
platform.d.ts
@@ -454,6 +455,16 @@
wrap-layout.d.ts
+
+ background.d.ts
+
+
+ background.d.ts
+
+
+
+ background.d.ts
+
css-selector.d.ts
@@ -699,6 +710,7 @@
+
PreserveNewest
@@ -1588,6 +1600,9 @@
PreserveNewest
+
+
+
diff --git a/apps/tests/pages/background-test.ts b/apps/tests/pages/background-test.ts
index aebd801e8..5e94e51ae 100644
--- a/apps/tests/pages/background-test.ts
+++ b/apps/tests/pages/background-test.ts
@@ -1,8 +1,15 @@
import observable = require("data/observable");
import pages = require("ui/page");
+var vm = new observable.Observable();
// Event handler for Page "loaded" event attached in main-page.xml
export function pageLoaded(args: observable.EventData) {
+ vm.set("style", "background-image: url('~/tests/pages/test2.png'); \nborder-color: green; \nborder-radius: 20; \nborder-width: 4;");
// Get the event sender
var page = args.object;
+ page.bindingContext = vm;
+}
+
+export function applyTap(args){
+ args.object.parent.style = vm.get("style");
}
\ No newline at end of file
diff --git a/apps/tests/pages/background-test.xml b/apps/tests/pages/background-test.xml
index eaae8b95c..89b1d1cda 100644
--- a/apps/tests/pages/background-test.xml
+++ b/apps/tests/pages/background-test.xml
@@ -1,5 +1,6 @@
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/apps/tests/ui/style/style-tests.ts b/apps/tests/ui/style/style-tests.ts
index 23c26253b..0a2aabeaa 100644
--- a/apps/tests/ui/style/style-tests.ts
+++ b/apps/tests/ui/style/style-tests.ts
@@ -22,7 +22,7 @@ export function test_css_dataURI_is_applied_to_backgroundImageSource() {
var page = views[1];
page.css = "StackLayout { background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC;') }";
- var value = stack.style._getValue(styleModule.backgroundImageSourceProperty);
+ var value = undefined; //stack.style._getValue(styleModule.backgroundImageSourceProperty);
TKUnit.assert(value !== undefined, "Style background-image not loaded correctly from data URI.");
});
diff --git a/js-libs/reworkcss-value/LICENSE b/js-libs/reworkcss-value/LICENSE
new file mode 100644
index 000000000..0c331f11a
--- /dev/null
+++ b/js-libs/reworkcss-value/LICENSE
@@ -0,0 +1,9 @@
+(The MIT License)
+
+Copyright (c) 2013 TJ Holowaychuk
+
+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.
\ No newline at end of file
diff --git a/js-libs/reworkcss-value/Readme.md b/js-libs/reworkcss-value/Readme.md
new file mode 100644
index 000000000..e31493542
--- /dev/null
+++ b/js-libs/reworkcss-value/Readme.md
@@ -0,0 +1,45 @@
+
+# css-value
+
+ WIP CSS value parser
+
+## Example
+
+The CSS value string "1px 0 0 5% .5px .10 1.5" yields:
+
+```js
+[
+ { type: 'number', string: '1px', unit: 'px', value: 1 },
+ { type: 'number', string: '0', unit: '', value: 0 },
+ { type: 'number', string: '0', unit: '', value: 0 },
+ { type: 'number', string: '5%', unit: '%', value: 5 },
+ { type: 'number', string: '.5px', unit: 'px', value: .5 },
+ { type: 'number', string: '.10', unit: '', value: .1 },
+ { type: 'number', string: '1.5', unit: '', value: 1.5 }
+]
+```
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2013 TJ Holowaychuk <tj@vision-media.ca>
+
+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.
diff --git a/js-libs/reworkcss-value/package.json b/js-libs/reworkcss-value/package.json
new file mode 100644
index 000000000..2c1199986
--- /dev/null
+++ b/js-libs/reworkcss-value/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "reworkcss-value.js",
+ "version": "0.0.1",
+ "description": "CSS value parser",
+ "keywords": ["css", "parser", "value"],
+ "author": "TJ Holowaychuk ",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/visionmedia/css-value.git"
+ },
+ "main": "reworkcss-value.js"
+}
diff --git a/js-libs/reworkcss-value/reworkcss-value.d.ts b/js-libs/reworkcss-value/reworkcss-value.d.ts
new file mode 100644
index 000000000..3b2d7e3cd
--- /dev/null
+++ b/js-libs/reworkcss-value/reworkcss-value.d.ts
@@ -0,0 +1,10 @@
+declare module "js-libs/reworkcss-value" {
+ export interface CSSValue {
+ type: string;
+ string: string;
+ unit: string;
+ value: number;
+ }
+
+ export function parse(cssValue: string): Array;
+}
diff --git a/js-libs/reworkcss-value/reworkcss-value.js b/js-libs/reworkcss-value/reworkcss-value.js
new file mode 100644
index 000000000..3aca66f11
--- /dev/null
+++ b/js-libs/reworkcss-value/reworkcss-value.js
@@ -0,0 +1,113 @@
+
+module.exports.parse = parse;
+
+function parse(str) {
+ return new Parser(str).parse();
+}
+
+function Parser(str) {
+ this.str = str;
+}
+
+Parser.prototype.skip = function(m){
+ this.str = this.str.slice(m[0].length);
+};
+
+Parser.prototype.comma = function(){
+ var m = /^, */.exec(this.str);
+ if (!m) return;
+ this.skip(m);
+ return { type: 'comma', string: ',' };
+};
+
+Parser.prototype.ident = function(){
+ var m = /^([\w-]+) */.exec(this.str);
+ if (!m) return;
+ this.skip(m);
+ return {
+ type: 'ident',
+ string: m[1]
+ }
+};
+
+Parser.prototype.int = function(){
+ var m = /^((\d+)(\S+)?) */.exec(this.str);
+ if (!m) return;
+ this.skip(m);
+ var n = ~~m[2];
+ var u = m[3];
+
+ return {
+ type: 'number',
+ string: m[1],
+ unit: u || '',
+ value: n
+ }
+};
+
+Parser.prototype.float = function(){
+ var m = /^(((?:\d+)?\.\d+)(\S+)?) */.exec(this.str);
+ if (!m) return;
+ this.skip(m);
+ var n = parseFloat(m[2]);
+ var u = m[3];
+
+ return {
+ type: 'number',
+ string: m[1],
+ unit: u || '',
+ value: n
+ }
+};
+
+Parser.prototype.number = function(){
+ return this.float() || this.int();
+};
+
+Parser.prototype.double = function(){
+ var m = /^"([^"]*)" */.exec(this.str);
+ if (!m) return m;
+ this.skip(m);
+ return {
+ type: 'string',
+ quote: '"',
+ string: '"' + m[1] + '"',
+ value: m[1]
+ }
+};
+
+Parser.prototype.single = function(){
+ var m = /^'([^']*)' */.exec(this.str);
+ if (!m) return m;
+ this.skip(m);
+ return {
+ type: 'string',
+ quote: "'",
+ string: "'" + m[1] + "'",
+ value: m[1]
+ }
+};
+
+Parser.prototype.string = function(){
+ return this.single() || this.double();
+};
+
+
+Parser.prototype.value = function(){
+ return this.number()
+ || this.ident()
+ || this.string()
+ || this.comma();
+};
+
+Parser.prototype.parse = function(){
+ var vals = [];
+
+ while (this.str.length) {
+ var obj = this.value();
+ if (!obj) throw new Error('failed to parse near `' + this.str.slice(0, 10) + '...`');
+ vals.push(obj);
+ }
+
+ return vals;
+};
diff --git a/ui/core/view.ios.ts b/ui/core/view.ios.ts
index c30bfd2d3..2b36260ce 100644
--- a/ui/core/view.ios.ts
+++ b/ui/core/view.ios.ts
@@ -3,7 +3,7 @@ import trace = require("trace");
import utils = require("utils/utils");
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
-import style = require("ui/styling/style");
+import background = require("ui/styling/background");
// merge the exports of the common file with the exports of this file
declare var exports;
@@ -207,57 +207,11 @@ export class View extends viewCommon.View {
}
private _onBoundsChanged() {
- var nativeView: UIView = this._nativeView;
- var imageSource = this.style._getValue(style.backgroundImageSourceProperty);
- if (imageSource && imageSource.ios) {
- var img = imageSource.ios;
- var frame = nativeView.frame;
- console.log("Frame: " + NSStringFromCGRect(frame));
- console.log("ImageSize: " + NSStringFromCGSize(img.size));
- if (frame.size.width > 0 && frame.size.height) {
- var repeatX = false;
- var repeatY = false;
- var posX = 15;
- var posY = 35;
- var sizeX = 15;
- var sizeY = 40;
-
- if (sizeX > 0 && sizeY > 0) {
- var resizeRect = CGRectMake(0, 0, sizeX, sizeY);
- UIGraphicsBeginImageContext(resizeRect.size);
- img.drawInRect(resizeRect);
- img = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- }
-
- UIGraphicsBeginImageContextWithOptions(frame.size, false, 1.0);
- if (!repeatX && !repeatY) {
- img.drawAtPoint(CGPointMake(posX, posY));
- }
- else {
- var w = repeatX ? frame.size.width : img.size.width;
- var h = repeatY ? frame.size.height : img.size.height;
-
- var context = UIGraphicsGetCurrentContext();
- CGContextSetPatternPhase(context, CGSizeMake(posX, posY));
- console.log("context" + context);
-
- posX = repeatX ? 0 : posX;
- posY = repeatY ? 0 : posY;
-
- var patternRect = CGRectMake(posX, posY, w, h);
- console.log("patternRect: " + NSStringFromCGRect(patternRect));
-
- img.drawAsPatternInRect(patternRect);
- }
- var bkgImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- console.log("bkgImage.size: " + NSStringFromCGSize(bkgImage.size));
- nativeView.backgroundColor = UIColor.alloc().initWithPatternImage(bkgImage);
- }
+ var bgColor = background.ios.createBackgroundUIColor(this);
+ if (bgColor) {
+ this._nativeView.backgroundColor = bgColor;
}
}
-
}
export class CustomLayoutView extends View {
diff --git a/ui/enums/enums.d.ts b/ui/enums/enums.d.ts
index f5bc4f01a..ef08a32cc 100644
--- a/ui/enums/enums.d.ts
+++ b/ui/enums/enums.d.ts
@@ -402,4 +402,14 @@
export var bold: string;
}
+
+ /**
+ * Specifies nackground repeat.
+ */
+ export module BackgroundRepeat {
+ export var repeat: string;
+ export var repeatX: string;
+ export var repeatY: string;
+ export var noRepeat: string;
+ }
}
\ No newline at end of file
diff --git a/ui/enums/enums.ts b/ui/enums/enums.ts
index 273ef9858..bc3429fa3 100644
--- a/ui/enums/enums.ts
+++ b/ui/enums/enums.ts
@@ -113,3 +113,10 @@ export module FontWeight {
export var normal: string = "normal";
export var bold: string = "bold";
}
+
+export module BackgroundRepeat {
+ export var repeat: string = "repeat";
+ export var repeatX: string = "repeat-x";
+ export var repeatY: string = "repeat-y";
+ export var noRepeat: string = "no-repeat";
+}
\ No newline at end of file
diff --git a/ui/styling/background-common.ts b/ui/styling/background-common.ts
new file mode 100644
index 000000000..8dba89aca
--- /dev/null
+++ b/ui/styling/background-common.ts
@@ -0,0 +1,195 @@
+import imageSource = require("image-source");
+import colorModule = require("color");
+import viewModule = require("ui/core/view");
+import style = require("ui/styling/style");
+import types = require("utils/types");
+import view = require("ui/core/view");
+import enums = require("ui/enums");
+import utils = require("utils/utils");
+import dts = require("ui/styling/background");
+import cssValue = require("js-libs/reworkcss-value");
+
+export class Background implements dts.Background {
+ public static default = new Background(undefined, undefined, undefined, undefined, undefined);
+
+ color: colorModule.Color;
+ image: imageSource.ImageSource;
+ repeat: string;
+ position: string;
+ size: string;
+
+ constructor(
+ color: colorModule.Color,
+ image: imageSource.ImageSource,
+ repeat: string,
+ position: string,
+ size: string) {
+
+ this.color = color;
+ this.image = image;
+ this.repeat = repeat;
+ this.position = position;
+ this.size = size;
+ }
+
+ public withColor(value: colorModule.Color): Background {
+ return new Background(value, this.image, this.repeat, this.position, this.size);
+ }
+
+ public withImage(value: imageSource.ImageSource): Background {
+ return new Background(this.color, value, this.repeat, this.position, this.size);
+ }
+
+ public withRepeat(value: string): Background {
+ return new Background(this.color, this.image, value, this.position, this.size);
+ }
+
+ public withPosition(value: string): Background {
+ return new Background(this.color, this.image, this.repeat, value, this.size);
+ }
+
+ public withSize(value: string): Background {
+ return new Background(this.color, this.image, this.repeat, this.position, value);
+ }
+
+ public getDrawParams(width: number, height: number): dts.BackgroundDrawParams {
+ if (!this.image) {
+ return null;
+ }
+
+ var res: dts.BackgroundDrawParams = {
+ repeatX: true,
+ repeatY: true,
+ posX: 0,
+ posY: 0,
+ }
+
+
+ // repeat
+ if (this.repeat) {
+ switch (this.repeat.toLowerCase()) {
+ case enums.BackgroundRepeat.noRepeat:
+ res.repeatX = false;
+ res.repeatY = false;
+ break;
+
+ case enums.BackgroundRepeat.repeatX:
+ res.repeatY = false;
+ break;
+
+ case enums.BackgroundRepeat.repeatY:
+ res.repeatX = false;
+ break;
+ }
+ }
+
+ var imageWidth = this.image.width;
+ var imageHeight = this.image.height;
+
+ // size
+ if (this.size) {
+ let values = cssValue.parse(this.size);
+ console.log("this.size values: " + JSON.stringify(values));
+ if (values.length === 2) {
+ let vx = values[0];
+ let vy = values[1];
+ if (vx.unit === "%" && vy.unit === "%") {
+ imageWidth = width * vx.value / 100;
+ imageHeight = height * vy.value / 100;
+
+ res.sizeX = imageWidth;
+ res.sizeY = imageHeight;
+ }
+ else if (vx.type === "number" && vy.type === "number" &&
+ ((vx.unit === "px" && vy.unit === "px") || (vx.unit === "" && vy.unit === ""))) {
+ imageWidth = vx.value;
+ imageHeight = vy.value;
+
+ res.sizeX = imageWidth;
+ res.sizeY = imageHeight;
+ }
+ }
+ else if (values.length === 1 && values[0].type === "ident") {
+ let scale = 0;
+
+ if (values[0].string === "cover") {
+ scale = Math.max(width / imageWidth, height / imageHeight);
+ }
+ else if (values[0].string === "contain") {
+ scale = Math.min(width / imageWidth, height / imageHeight);
+ }
+
+ if(scale > 0){
+ imageWidth *= scale;
+ imageHeight *= scale;
+
+ res.sizeX = imageWidth;
+ res.sizeY = imageHeight;
+ }
+ }
+ }
+
+ // position
+ if (this.position) {
+ let values = cssValue.parse(this.position);
+ console.log("this.position values: " + JSON.stringify(values));
+
+ let spaceX = width - imageWidth;
+ let spaceY = height - imageHeight;
+
+ if (values.length === 2) {
+ let vx = values[0];
+ let vy = values[1];
+
+ if (vx.unit === "%" && vy.unit === "%") {
+ res.posX = spaceX * vx.value / 100;
+ res.posY = spaceY * vy.value / 100;
+ }
+ else if (vx.type === "number" && vy.type === "number" &&
+ ((vx.unit === "px" && vy.unit === "px") || (vx.unit === "" && vy.unit === ""))) {
+ res.posX = vx.value;
+ res.posY = vy.value;
+ }
+ else if (vx.type === "ident" && vy.type === "ident") {
+ if (vx.string.toLowerCase() === "center") {
+ res.posX = spaceX / 2;
+ }
+ else if (vx.string.toLowerCase() === "right") {
+ res.posX = spaceX;
+ }
+
+ if (vy.string.toLowerCase() === "center") {
+ res.posY = spaceY / 2;
+ }
+ else if (vy.string.toLowerCase() === "bottom") {
+ res.posY = spaceY;
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public isEmpty(): boolean {
+ return types.isUndefined(this.image) && types.isUndefined(this.color);
+ }
+
+ public static equals(value1: Background, value2: Background): boolean {
+ // both values are falsy
+ if (!value1 && !value2) {
+ return true;
+ }
+
+ // only one is falsy
+ if (!value1 || !value2) {
+ return false;
+ }
+
+ return value1.image === value2.image &&
+ value1.position === value2.position &&
+ value1.repeat === value2.repeat &&
+ value1.size === value2.size &&
+ colorModule.Color.equals(value1.color, value2.color);
+ }
+}
diff --git a/ui/styling/background.android.ts b/ui/styling/background.android.ts
new file mode 100644
index 000000000..8ddf0e131
--- /dev/null
+++ b/ui/styling/background.android.ts
@@ -0,0 +1,134 @@
+import imageSource = require("image-source");
+import colorModule = require("color");
+import viewModule = require("ui/core/view");
+import style = require("ui/styling/style");
+import types = require("utils/types");
+import view = require("ui/core/view");
+import enums = require("ui/enums");
+import utils = require("utils/utils");
+import common = require("ui/styling/background-common");
+import dts = require("ui/styling/background");
+
+declare var exports;
+require("utils/module-merge").merge(common, exports);
+
+// We are using "ad" here to avoid namespace collision with the global android object
+export module ad {
+ export class BorderGradientDrawable extends android.graphics.drawable.GradientDrawable implements dts.ad.BorderGradientDrawable {
+ private _density = utils.layout.getDisplayDensity();
+
+ constructor() {
+ super();
+
+ return global.__native(this);
+ }
+
+ private _borderWidth: number;
+ get borderWidth(): number {
+ return this._borderWidth;
+ }
+ set borderWidth(value: number) {
+ if (this._borderWidth !== value) {
+ this._borderWidth = value;
+
+ this.setStroke(this._borderWidth * this._density, this._borderColor);
+ }
+ }
+
+ private _cornerRadius: number;
+ get cornerRadius(): number {
+ return this._cornerRadius;
+ }
+ set cornerRadius(value: number) {
+ if (this._cornerRadius !== value) {
+ this._cornerRadius = value;
+
+ this.setCornerRadius(this._cornerRadius * this._density);
+ }
+ }
+
+ private _borderColor: number;
+ get borderColor(): number {
+ return this._borderColor;
+ }
+ set borderColor(value: number) {
+ if (this._borderColor !== value) {
+ this._borderColor = value;
+
+ this.setStroke(this._borderWidth * this._density, this._borderColor);
+ }
+ }
+
+ private _background: common.Background
+ get background(): common.Background {
+ return this._background;
+ }
+ set background(value: common.Background) {
+ if (this._background !== value) {
+ this._background = value;
+
+ this.invalidateSelf();
+ }
+ }
+
+ public draw(canvas: android.graphics.Canvas): void {
+ super.draw(canvas);
+ console.log("BorderGradientDrawable.draw()");
+ var bounds = this.getBounds();
+ var boundsWidth = bounds.width();
+ var boundsHeight = bounds.height();
+
+ if (this.background && !this.background.isEmpty() && boundsWidth > 0 && boundsHeight > 0) {
+ var bitmap = this.background.image.android;
+
+ var radius = this._cornerRadius * this._density;
+ var stroke = this._borderWidth * this._density;
+ var bounds = this.getBounds();
+
+ // TODO: check this path
+ var path = new android.graphics.Path();
+ path.addRoundRect(new android.graphics.RectF(stroke, stroke, bounds.right - stroke, bounds.bottom - stroke), radius, radius, android.graphics.Path.Direction.CW);
+ canvas.clipPath(path);
+
+ if (this.background.color && this.background.color.android) {
+ var c = this.background.color;
+ canvas.drawARGB(c.a, c.r, c.g, c.b);
+ }
+
+ if (this.background.image) {
+ var params = this.background.getDrawParams(boundsWidth, boundsHeight);
+
+ var matrix = new android.graphics.Matrix();
+ if (params.sizeX > 0 && params.sizeY > 0) {
+ var scaleX = params.sizeX / bitmap.getWidth();
+ var scaleY = params.sizeY / bitmap.getHeight();
+ matrix.setScale(scaleX, scaleY, 0, 0);
+ }
+ else {
+ params.sizeX = bitmap.getWidth();
+ params.sizeY = bitmap.getHeight();
+ }
+ matrix.postTranslate(params.posX, params.posY);
+
+ if (!params.repeatX && !params.repeatY) {
+ canvas.drawBitmap(bitmap, matrix, undefined);
+ }
+ else {
+ var shader = new android.graphics.BitmapShader(bitmap, android.graphics.Shader.TileMode.REPEAT, android.graphics.Shader.TileMode.REPEAT);
+ shader.setLocalMatrix(matrix);
+ var paint = new android.graphics.Paint();
+ paint.setShader(shader);
+
+ var w = params.repeatX ? bounds.width() : params.sizeX;
+ var h = params.repeatY ? bounds.height() : params.sizeY;
+
+ params.posX = params.repeatX ? 0 : params.posX;
+ params.posY = params.repeatY ? 0 : params.posY;
+
+ canvas.drawRect(params.posX, params.posY, params.posX + w, params.posY + h, paint);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/ui/styling/background.d.ts b/ui/styling/background.d.ts
new file mode 100644
index 000000000..83704681a
--- /dev/null
+++ b/ui/styling/background.d.ts
@@ -0,0 +1,64 @@
+declare module "ui/styling/background" {
+ import imageSource = require("image-source");
+ import colorModule = require("color");
+ import viewModule = require("ui/core/view");
+ import style = require("ui/styling/style");
+ import types = require("utils/types");
+ import view = require("ui/core/view");
+ import enums = require("ui/enums");
+ import utils = require("utils/utils");
+
+ export interface BackgroundDrawParams {
+ repeatX: boolean;
+ repeatY: boolean;
+ posX: number;
+ posY: number;
+ sizeX?: number;
+ sizeY?: number;
+ }
+
+ export class Background {
+ static default: Background;
+ color: colorModule.Color;
+ image: imageSource.ImageSource;
+ repeat: string;
+ position: string;
+ size: string;
+
+ constructor(
+ color: colorModule.Color,
+ image: imageSource.ImageSource,
+ repeat: string,
+ position: string,
+ size: string);
+
+ public withColor(value: colorModule.Color): Background;
+ public withImage(value: imageSource.ImageSource): Background;
+
+ public withRepeat(value: string): Background;
+
+ public withPosition(value: string): Background;
+
+ public withSize(value: string): Background;;
+
+ public getDrawParams(width: number, height: number): BackgroundDrawParams;
+
+ public isEmpty(): boolean;
+
+ public static equals(value1: Background, value2: Background): boolean;
+ }
+
+ export module ios {
+ export function createBackgroundUIColor(view: viewModule.View): UIColor;
+ }
+
+ // We are using "ad" here to avoid namespace collision with the global android object
+ export module ad {
+ export class BorderGradientDrawable extends android.graphics.drawable.GradientDrawable {
+ borderWidth: number;
+ cornerRadius: number;
+ borderColor: number;
+ background: Background;
+ }
+ }
+}
diff --git a/ui/styling/background.ios.ts b/ui/styling/background.ios.ts
new file mode 100644
index 000000000..d06c90ab7
--- /dev/null
+++ b/ui/styling/background.ios.ts
@@ -0,0 +1,74 @@
+import imageSource = require("image-source");
+import colorModule = require("color");
+import viewModule = require("ui/core/view");
+import style = require("ui/styling/style");
+import types = require("utils/types");
+import view = require("ui/core/view");
+import enums = require("ui/enums");
+import utils = require("utils/utils");
+import common = require("ui/styling/background-common");
+import dts = require("ui/styling/background");
+
+declare var exports;
+require("utils/module-merge").merge(common, exports);
+
+export module ios {
+ export function createBackgroundUIColor(view: viewModule.View): UIColor {
+ var background = view.style._getValue(style.backgroundInternalProperty);
+ var frame = (view._nativeView).frame;
+ var result: UIColor;
+
+ if (background && !background.isEmpty() && frame.size.width > 0 && frame.size.height) {
+ console.log("Frame: " + NSStringFromCGRect(frame));
+
+ if (!background.image) {
+ result = background.color.ios;
+ }
+ else {
+ var img = background.image.ios;
+ console.log("ImageSize: " + NSStringFromCGSize(img.size));
+ var params = background.getDrawParams(frame.size.width, frame.size.height);
+
+ if (params.sizeX > 0 && params.sizeY > 0) {
+ var resizeRect = CGRectMake(0, 0, params.sizeX, params.sizeY);
+ UIGraphicsBeginImageContext(resizeRect.size);
+ img.drawInRect(resizeRect);
+ img = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+ }
+
+ UIGraphicsBeginImageContextWithOptions(frame.size, false, 1.0);
+ var context = UIGraphicsGetCurrentContext();
+
+ if (background.color && background.color.ios) {
+ CGContextSetFillColorWithColor(context, background.color.ios.CGColor);
+ CGContextFillRect(context, frame);
+ }
+
+ if (!params.repeatX && !params.repeatY) {
+ img.drawAtPoint(CGPointMake(params.posX, params.posY));
+ }
+ else {
+ var w = params.repeatX ? frame.size.width : img.size.width;
+ var h = params.repeatY ? frame.size.height : img.size.height;
+
+ CGContextSetPatternPhase(context, CGSizeMake(params.posX, params.posY));
+ console.log("context" + context);
+
+ params.posX = params.repeatX ? 0 : params.posX;
+ params.posY = params.repeatY ? 0 : params.posY;
+
+ var patternRect = CGRectMake(params.posX, params.posY, w, h);
+ console.log("patternRect: " + NSStringFromCGRect(patternRect));
+
+ img.drawAsPatternInRect(patternRect);
+ }
+ var bkgImage = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+ console.log("bkgImage.size: " + NSStringFromCGSize(bkgImage.size));
+ result = UIColor.alloc().initWithPatternImage(bkgImage);
+ }
+ return result;
+ }
+ }
+}
diff --git a/ui/styling/style.ts b/ui/styling/style.ts
index bcecc442a..ccb2d764c 100644
--- a/ui/styling/style.ts
+++ b/ui/styling/style.ts
@@ -12,6 +12,7 @@ import enums = require("ui/enums");
import imageSource = require("image-source");
import utils = require("utils/utils");
import font = require("ui/styling/font");
+import background = require("ui/styling/background");
// key is the property id and value is Dictionary;
var _registeredHandlers = Array