Merge branch 'flatstring'
This commit is contained in:
commit
b6379aab7b
11 changed files with 409 additions and 264 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,3 +2,5 @@ build
|
|||
.yotta.json
|
||||
yotta_modules
|
||||
yotta_targets
|
||||
*.swp
|
||||
Makefile
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
#ifndef MANAGED_STRING_H
|
||||
#define MANAGED_STRING_H
|
||||
|
||||
#include "mbed.h"
|
||||
#include "RefCounted.h"
|
||||
|
||||
struct StringData : RefCounted
|
||||
{
|
||||
uint16_t len;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class definition for a ManagedString.
|
||||
|
@ -14,21 +21,43 @@
|
|||
* 1) std::shared_ptr is not yet availiable on the ARMCC compiler
|
||||
* 2) to reduce memory footprint - we don't need many of the other features in the std library
|
||||
* 3) it makes an interestin case study for anyone interested in seeing how it works!
|
||||
* 4) we need explicit reference counting to inter-op with low-level application langauge runtimes
|
||||
* 5) the reference counting needs to also work for read-only, flash-resident strings
|
||||
*/
|
||||
class ManagedString
|
||||
{
|
||||
// Internally we record the string as a char *, but control access to this to proide immutability
|
||||
// and reference counting.
|
||||
char *data;
|
||||
int16_t *ref;
|
||||
int16_t len;
|
||||
// StringData contains the reference count, the length, follwed by char[] data, all in one block.
|
||||
// When referece count is 0xffff, then it's read only and should not be counted.
|
||||
// Otherwise the block was malloc()ed.
|
||||
// We control access to this to proide immutability and reference counting.
|
||||
StringData *ptr;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a managed string from a specially prepared string literal. It will ptr->incr().
|
||||
*
|
||||
* @param ptr The literal - first two bytes should be 0xff, then the length in little endian, then the literal. The literal has to be 4-byte aligned.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* static const char hello[] __attribute__ ((aligned (4))) = "\xff\xff\x05\x00" "Hello";
|
||||
* ManagedString s((StringData*)(void*)hello);
|
||||
* @endcode
|
||||
*/
|
||||
ManagedString(StringData *ptr);
|
||||
|
||||
/**
|
||||
* Get current ptr, do not decr() it, and set the current instance to empty string.
|
||||
* This is to be used by specialized runtimes which pass StringData around.
|
||||
*/
|
||||
StringData *leakData();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a managed string from a pointer to an 8-bit character buffer.
|
||||
* The buffer is copied to ensure sage memory management (the supplied
|
||||
* The buffer is copied to ensure safe memory management (the supplied
|
||||
* character buffer may be decalred on the stack for instance).
|
||||
*
|
||||
* @param str The character array on which to base the new ManagedString.
|
||||
|
@ -115,7 +144,7 @@ class ManagedString
|
|||
*
|
||||
* Free this ManagedString, and decrement the reference count to the
|
||||
* internal character buffer. If we're holding the last reference,
|
||||
* also free the character buffer and reference counter.
|
||||
* also free the character buffer.
|
||||
*/
|
||||
~ManagedString();
|
||||
|
||||
|
@ -251,11 +280,14 @@ class ManagedString
|
|||
|
||||
|
||||
/**
|
||||
* Provides an immutable 8 bit wide haracter buffer representing this string.
|
||||
* Provides an immutable 8 bit wide character buffer representing this string.
|
||||
*
|
||||
* @return a pointer to the character buffer.
|
||||
*/
|
||||
const char *toCharArray();
|
||||
const char *toCharArray() const
|
||||
{
|
||||
return ptr->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the length of this ManagedString in characters.
|
||||
|
@ -269,7 +301,10 @@ class ManagedString
|
|||
* print(s.length()) // prints "4"
|
||||
* @endcode
|
||||
*/
|
||||
int16_t length();
|
||||
int16_t length() const
|
||||
{
|
||||
return ptr->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty String constant
|
||||
|
|
|
@ -2,6 +2,14 @@
|
|||
#define MICROBIT_IMAGE_H
|
||||
|
||||
#include "mbed.h"
|
||||
#include "RefCounted.h"
|
||||
|
||||
struct ImageData : RefCounted
|
||||
{
|
||||
uint16_t width; // Width in pixels
|
||||
uint16_t height; // Height in pixels
|
||||
uint8_t data[0]; // 2D array representing the bitmap image
|
||||
};
|
||||
|
||||
/**
|
||||
* Class definition for a MicroBitImage.
|
||||
|
@ -11,9 +19,7 @@
|
|||
*/
|
||||
class MicroBitImage
|
||||
{
|
||||
int16_t width; // Width of the bitmap, in pixels.
|
||||
int16_t height; // Height of the bitmap, in pixels.
|
||||
int16_t *ref; // Reference count.
|
||||
ImageData *ptr; // Pointer to payload data
|
||||
|
||||
|
||||
/**
|
||||
|
@ -32,7 +38,34 @@ class MicroBitImage
|
|||
|
||||
public:
|
||||
static MicroBitImage EmptyImage; // Shared representation of a null image.
|
||||
uint8_t *bitmap; // 2D array representing the bitmap image.
|
||||
|
||||
/**
|
||||
* Get current ptr, do not decr() it, and set the current instance to empty image.
|
||||
* This is to be used by specialized runtimes which pass ImageData around.
|
||||
*/
|
||||
ImageData *leakData();
|
||||
|
||||
/**
|
||||
* Return a 2D array representing the bitmap image.
|
||||
*/
|
||||
uint8_t *getBitmap()
|
||||
{
|
||||
return ptr->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create an image from a specially prepared constant array, with no copying. Will call ptr->incr().
|
||||
*
|
||||
* @param ptr The literal - first two bytes should be 0xff, then width, 0, height, 0, and the bitmap. Width and height are 16 bit. The literal has to be 4-byte aligned.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* static const uint8_t heart[] __attribute__ ((aligned (4))) = { 0xff, 0xff, 10, 0, 5, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
|
||||
* MicroBitImage i((ImageData*)(void*)heart);
|
||||
* @endcode
|
||||
*/
|
||||
MicroBitImage(ImageData *ptr);
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
|
@ -325,7 +358,10 @@ class MicroBitImage
|
|||
* i.getWidth(); //equals 10...
|
||||
* @endcode
|
||||
*/
|
||||
int getWidth();
|
||||
int getWidth() const
|
||||
{
|
||||
return ptr->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the height of this image.
|
||||
|
@ -339,8 +375,28 @@ class MicroBitImage
|
|||
* i.getHeight(); //equals 5...
|
||||
* @endcode
|
||||
*/
|
||||
int getHeight();
|
||||
int getHeight() const
|
||||
{
|
||||
return ptr->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets number of bytes in the bitmap, ie., width * height.
|
||||
*
|
||||
* @return The size of the bitmap.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
|
||||
* MicroBitImage i(10,5,heart);
|
||||
* i.getSize(); //equals 50...
|
||||
* @endcode
|
||||
*/
|
||||
int getSize() const
|
||||
{
|
||||
return ptr->width * ptr->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the bitmap to a csv string.
|
||||
*
|
||||
|
@ -352,7 +408,7 @@ class MicroBitImage
|
|||
* @endcode
|
||||
*/
|
||||
ManagedString toString();
|
||||
|
||||
|
||||
/**
|
||||
* Crops the image to the given dimensions
|
||||
*
|
||||
|
@ -372,6 +428,17 @@ class MicroBitImage
|
|||
*/
|
||||
MicroBitImage crop(int startx, int starty, int finx, int finy);
|
||||
|
||||
/**
|
||||
* Check if image is read-only (i.e., residing in flash).
|
||||
*/
|
||||
bool isReadOnly();
|
||||
|
||||
/**
|
||||
* Create a copy of the image bitmap. Used particularly, when isReadOnly() is true.
|
||||
*
|
||||
* @return an instance of MicroBitImage which can be modified independently of the current instance
|
||||
*/
|
||||
MicroBitImage clone();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
34
inc/RefCounted.h
Normal file
34
inc/RefCounted.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef REF_COUNTED_H
|
||||
#define REF_COUNTED_H
|
||||
|
||||
#include "mbed.h"
|
||||
|
||||
/**
|
||||
* Base class for payload for ref-counted objects. Used by ManagedString and MicroBitImage.
|
||||
* There is no constructor, as this struct is typically malloc()ed.
|
||||
*/
|
||||
struct RefCounted
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The high 15 bits hold the number of outstanding references. The lowest bit is always 1
|
||||
* to make sure it doesn't look like vtable.
|
||||
* Should never be even or one (object should be deleted then).
|
||||
* When it's set to 0xffff, it means the object sits in flash and should not be counted.
|
||||
*/
|
||||
uint16_t refCount;
|
||||
|
||||
/** Increment reference count. */
|
||||
void incr();
|
||||
|
||||
/** Decrement reference count. */
|
||||
void decr();
|
||||
|
||||
/** Initializes for one outstanding reference. */
|
||||
void init();
|
||||
|
||||
/** Checks if the object sits in flash memory. */
|
||||
bool isReadOnly();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -28,6 +28,7 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
|
|||
"MicroBitSerial.cpp"
|
||||
"MicroBitHeapAllocator.cpp"
|
||||
"MicroBitListener.cpp"
|
||||
"RefCounted.cpp"
|
||||
"MemberFunctionCallback.cpp"
|
||||
"ble-services/MicroBitDFUService.cpp"
|
||||
"ble-services/MicroBitEventService.cpp"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "mbed.h"
|
||||
#include "MicroBit.h"
|
||||
|
||||
static const char empty[] __attribute__ ((aligned (4))) = "\xff\xff\0\0\0";
|
||||
|
||||
/**
|
||||
* Internal constructor helper.
|
||||
|
@ -10,11 +11,7 @@
|
|||
*/
|
||||
void ManagedString::initEmpty()
|
||||
{
|
||||
data = ManagedString::EmptyString.data;
|
||||
ref = ManagedString::EmptyString.ref;
|
||||
len = ManagedString::EmptyString.len;
|
||||
|
||||
(*ref)++;
|
||||
ptr = (StringData*)(void*)empty;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,13 +22,41 @@ void ManagedString::initString(const char *str)
|
|||
{
|
||||
// Initialise this ManagedString as a new string, using the data provided.
|
||||
// We assume the string is sane, and null terminated.
|
||||
len = strlen(str);
|
||||
data = (char *) malloc(len+1);
|
||||
memcpy(data, str, len+1);
|
||||
ref = (int16_t *) malloc(sizeof(int16_t));
|
||||
*ref = 1;
|
||||
int len = strlen(str);
|
||||
ptr = (StringData *) malloc(4+len+1);
|
||||
ptr->init();
|
||||
ptr->len = len;
|
||||
memcpy(ptr->data, str, len+1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a managed string from a specially prepared string literal. It will ptr->incr().
|
||||
*
|
||||
* @param ptr The literal - first two bytes should be 0xff, then the length in little endian, then the literal. The literal has to be 4-byte aligned.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* static const char hello[] __attribute__ ((aligned (4))) = "\xff\xff\x05\x00" "Hello";
|
||||
* ManagedString s((StringData*)(void*)hello);
|
||||
* @endcode
|
||||
*/
|
||||
ManagedString::ManagedString(StringData *p)
|
||||
{
|
||||
ptr = p;
|
||||
ptr->incr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current ptr, do not decr() it, and set the current instance to empty string.
|
||||
* This is to be used by specialized runtimes which pass StringData around.
|
||||
*/
|
||||
StringData* ManagedString::leakData()
|
||||
{
|
||||
StringData *res = ptr;
|
||||
initEmpty();
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
@ -65,7 +90,6 @@ ManagedString::ManagedString(const int value)
|
|||
*/
|
||||
ManagedString::ManagedString(const char value)
|
||||
{
|
||||
|
||||
char str[2] = {value, 0};
|
||||
initString(str);
|
||||
}
|
||||
|
@ -82,7 +106,7 @@ ManagedString::ManagedString(const char value)
|
|||
ManagedString::ManagedString(const char *str)
|
||||
{
|
||||
// Sanity check. Return EmptyString for anything distasteful
|
||||
if ((str == NULL || *str == 0) && this != &ManagedString::EmptyString)
|
||||
if (str == NULL || *str == 0)
|
||||
{
|
||||
initEmpty();
|
||||
return;
|
||||
|
@ -94,19 +118,17 @@ ManagedString::ManagedString(const char *str)
|
|||
ManagedString::ManagedString(const ManagedString &s1, const ManagedString &s2)
|
||||
{
|
||||
// Calculate length of new string.
|
||||
len = s1.len + s2.len;
|
||||
int len = s1.length() + s2.length();
|
||||
|
||||
// Create a new buffer for holding the new string data.
|
||||
data = (char *) malloc(len+1);
|
||||
ptr = (StringData*) malloc(4+len+1);
|
||||
ptr->init();
|
||||
ptr->len = len;
|
||||
|
||||
// Enter the data, and terminate the string.
|
||||
memcpy(data, s1.data, s1.len);
|
||||
memcpy(data + s1.len, s2.data, s2.len);
|
||||
data[len] = 0;
|
||||
|
||||
// Initialise the ref count and we're done.
|
||||
ref = (int16_t *) malloc(sizeof(int16_t));
|
||||
*ref = 1;
|
||||
memcpy(ptr->data, s1.toCharArray(), s1.length());
|
||||
memcpy(ptr->data + s1.length(), s2.toCharArray(), s2.length());
|
||||
ptr->data[len] = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -133,17 +155,14 @@ ManagedString::ManagedString(const char *str, const int16_t length)
|
|||
return;
|
||||
}
|
||||
|
||||
// Store the length of the new string
|
||||
len = length;
|
||||
|
||||
// Allocate a new buffer, and create a NULL terminated string.
|
||||
data = (char *) malloc(len+1);
|
||||
memcpy(data, str, len);
|
||||
data[len] = 0;
|
||||
|
||||
// Initialize a refcount and we're done.
|
||||
ref = (int16_t *) malloc(sizeof(int16_t));
|
||||
*ref = 1;
|
||||
ptr = (StringData*) malloc(4+length+1);
|
||||
ptr->init();
|
||||
// Store the length of the new string
|
||||
ptr->len = length;
|
||||
memcpy(ptr->data, str, length);
|
||||
ptr->data[length] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,11 +180,8 @@ ManagedString::ManagedString(const char *str, const int16_t length)
|
|||
*/
|
||||
ManagedString::ManagedString(const ManagedString &s)
|
||||
{
|
||||
data = s.data;
|
||||
ref = s.ref;
|
||||
len = s.len;
|
||||
|
||||
(*ref)++;
|
||||
ptr = s.ptr;
|
||||
ptr->incr();
|
||||
}
|
||||
|
||||
|
||||
|
@ -193,11 +209,7 @@ ManagedString::ManagedString()
|
|||
*/
|
||||
ManagedString::~ManagedString()
|
||||
{
|
||||
if(--(*ref) == 0)
|
||||
{
|
||||
free(data);
|
||||
free(ref);
|
||||
}
|
||||
ptr->decr();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -220,19 +232,12 @@ ManagedString::~ManagedString()
|
|||
*/
|
||||
ManagedString& ManagedString::operator = (const ManagedString& s)
|
||||
{
|
||||
if(this == &s)
|
||||
if (this->ptr == s.ptr)
|
||||
return *this;
|
||||
|
||||
if(--(*ref) == 0)
|
||||
{
|
||||
free(data);
|
||||
free(ref);
|
||||
}
|
||||
|
||||
data = s.data;
|
||||
ref = s.ref;
|
||||
len = s.len;
|
||||
(*ref)++;
|
||||
ptr->decr();
|
||||
ptr = s.ptr;
|
||||
ptr->incr();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -258,7 +263,7 @@ ManagedString& ManagedString::operator = (const ManagedString& s)
|
|||
*/
|
||||
bool ManagedString::operator== (const ManagedString& s)
|
||||
{
|
||||
return ((len == s.len) && (memcmp(data,s.data,len)==0));
|
||||
return ((length() == s.length()) && (strcmp(toCharArray(),s.toCharArray())==0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -282,7 +287,7 @@ bool ManagedString::operator== (const ManagedString& s)
|
|||
*/
|
||||
bool ManagedString::operator< (const ManagedString& s)
|
||||
{
|
||||
return (memcmp(data, s.data,min(len,s.len))<0);
|
||||
return (strcmp(toCharArray(), s.toCharArray())<0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -306,7 +311,7 @@ bool ManagedString::operator< (const ManagedString& s)
|
|||
*/
|
||||
bool ManagedString::operator> (const ManagedString& s)
|
||||
{
|
||||
return (memcmp(data, s.data,min(len,s.len))>0);
|
||||
return (strcmp(toCharArray(), s.toCharArray())>0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -326,14 +331,14 @@ bool ManagedString::operator> (const ManagedString& s)
|
|||
ManagedString ManagedString::substring(int16_t start, int16_t length)
|
||||
{
|
||||
// If the parameters are illegal, just return a reference to the empty string.
|
||||
if (start >= len)
|
||||
if (start >= this->length())
|
||||
return ManagedString(ManagedString::EmptyString);
|
||||
|
||||
// Compute a safe copy length;
|
||||
length = min(len-start, length);
|
||||
length = min(this->length()-start, length);
|
||||
|
||||
// Build a ManagedString from this.
|
||||
return ManagedString(data+start, length);
|
||||
return ManagedString(toCharArray()+start, length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -353,19 +358,13 @@ ManagedString ManagedString::substring(int16_t start, int16_t length)
|
|||
ManagedString ManagedString::operator+ (ManagedString& s)
|
||||
{
|
||||
// If the other string is empty, nothing to do!
|
||||
if(s.len == 0)
|
||||
if(s.length() == 0)
|
||||
return *this;
|
||||
|
||||
if (len == 0)
|
||||
return s;
|
||||
|
||||
if(s == ManagedString::EmptyString)
|
||||
return *this;
|
||||
|
||||
if(*this == ManagedString::EmptyString)
|
||||
if (length() == 0)
|
||||
return s;
|
||||
|
||||
return ManagedString(data, s.data);
|
||||
return ManagedString(*this, s);
|
||||
}
|
||||
|
||||
|
||||
|
@ -384,39 +383,10 @@ ManagedString ManagedString::operator+ (ManagedString& s)
|
|||
*/
|
||||
char ManagedString::charAt(int16_t index)
|
||||
{
|
||||
return (index >=0 && index < len) ? data[index] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an immutable 8 bit wide haracter buffer representing this string.
|
||||
*
|
||||
* @return a pointer to the charcter buffer.
|
||||
*/
|
||||
const char *ManagedString::toCharArray()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the length of this ManagedString in characters.
|
||||
*
|
||||
* @return the length of the string in characters.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedString s("abcd");
|
||||
*
|
||||
* print(s.length()) // prints "4"
|
||||
* @endcode
|
||||
*/
|
||||
int16_t ManagedString::length()
|
||||
{
|
||||
return len;
|
||||
return (index >=0 && index < length()) ? ptr->data[index] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty string constant literal
|
||||
*/
|
||||
ManagedString ManagedString::EmptyString("\0");
|
||||
|
||||
|
||||
ManagedString ManagedString::EmptyString((StringData*)(void*)empty);
|
||||
|
|
|
@ -122,7 +122,9 @@ void MicroBit::init()
|
|||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE)
|
||||
DeviceInformationService ble_device_information_service (*ble, MICROBIT_BLE_MANUFACTURER, MICROBIT_BLE_MODEL, getSerial().toCharArray(), MICROBIT_BLE_HARDWARE_VERSION, MICROBIT_BLE_FIRMWARE_VERSION, MICROBIT_BLE_SOFTWARE_VERSION);
|
||||
// Create a temporary, so that compiler doesn't delete the pointer before DeviceInformationService copies it
|
||||
ManagedString tmp = getSerial();
|
||||
DeviceInformationService ble_device_information_service (*ble, MICROBIT_BLE_MANUFACTURER, MICROBIT_BLE_MODEL, tmp.toCharArray(), MICROBIT_BLE_HARDWARE_VERSION, MICROBIT_BLE_FIRMWARE_VERSION, MICROBIT_BLE_SOFTWARE_VERSION);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_EVENT_SERVICE)
|
||||
|
@ -233,7 +235,7 @@ ManagedString MicroBit::getSerial()
|
|||
ManagedString s1 = ManagedString(n1);
|
||||
ManagedString s2 = ManagedString(n2);
|
||||
|
||||
return s1+s2;
|
||||
return s1 + s2;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -126,7 +126,7 @@ void MicroBitDisplay::render()
|
|||
y = height - 1 - t;
|
||||
}
|
||||
|
||||
if(image.bitmap[y*(width*2)+x])
|
||||
if(image.getBitmap()[y*(width*2)+x])
|
||||
coldata |= (1 << i);
|
||||
}
|
||||
|
||||
|
@ -175,7 +175,7 @@ void MicroBitDisplay::renderGreyscale()
|
|||
y = height - 1 - t;
|
||||
}
|
||||
|
||||
if(min(image.bitmap[y * (width * 2) + x],brightness) & greyscaleBitMsk)
|
||||
if(min(image.getBitmap()[y * (width * 2) + x],brightness) & greyscaleBitMsk)
|
||||
coldata |= (1 << i);
|
||||
}
|
||||
//write the new bit pattern
|
||||
|
|
|
@ -77,7 +77,7 @@ void microbit_heap_print(HeapDefinition &heap)
|
|||
while (block < heap.heap_end)
|
||||
{
|
||||
blockSize = *block & ~MICROBIT_HEAP_BLOCK_FREE;
|
||||
uBit.serialpc.printf("[%C:%d] ", *block & MICROBIT_HEAP_BLOCK_FREE ? 'F' : 'U', blockSize*4);
|
||||
uBit.serial.printf("[%C:%d] ", *block & MICROBIT_HEAP_BLOCK_FREE ? 'F' : 'U', blockSize*4);
|
||||
if (cols++ == 20)
|
||||
{
|
||||
uBit.serial.printf("\n");
|
||||
|
@ -329,7 +329,7 @@ void *microbit_malloc(size_t size)
|
|||
if (p != NULL)
|
||||
{
|
||||
#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
|
||||
pc.uBit.serial("microbit_malloc: ALLOCATED: %d [%p]\n", size, p);
|
||||
uBit.serial.printf("microbit_malloc: ALLOCATED: %d [%p]\n", size, p);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
@ -345,7 +345,7 @@ void *microbit_malloc(size_t size)
|
|||
#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
|
||||
// Keep everything trasparent if we've not been initialised yet
|
||||
if (microbit_active_heaps())
|
||||
pc.uBit.serial("microbit_malloc: NATIVE ALLOCATED: %d [%p]\n", size, p);
|
||||
uBit.serial.printf("microbit_malloc: NATIVE ALLOCATED: %d [%p]\n", size, p);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
@ -354,7 +354,7 @@ void *microbit_malloc(size_t size)
|
|||
#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
|
||||
// Keep everything trasparent if we've not been initialised yet
|
||||
if (microbit_active_heaps())
|
||||
pc.uBit.serial("microbit_malloc: OUT OF MEMORY\n");
|
||||
uBit.serial.printf("microbit_malloc: OUT OF MEMORY\n");
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_PANIC_HEAP_FULL)
|
||||
|
@ -375,7 +375,7 @@ void microbit_free(void *mem)
|
|||
|
||||
#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
|
||||
if (microbit_active_heaps())
|
||||
pc.uBit.serial("microbit_free: %p\n", mem);
|
||||
uBit.serial.printf("microbit_free: %p\n", mem);
|
||||
#endif
|
||||
// Sanity check.
|
||||
if (memory == NULL)
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
|
||||
#include "MicroBit.h"
|
||||
|
||||
|
||||
/*
|
||||
* The null image. We actally create a small one byte buffer here, just to keep NULL pointers out of the equation.
|
||||
*/
|
||||
MicroBitImage MicroBitImage::EmptyImage(1,1);
|
||||
static const uint16_t empty[] __attribute__ ((aligned (4))) = { 0xffff, 1, 1, 0, };
|
||||
MicroBitImage MicroBitImage::EmptyImage((ImageData*)(void*)empty);
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
|
@ -65,12 +67,8 @@ MicroBitImage::MicroBitImage(const int16_t x, const int16_t y)
|
|||
*/
|
||||
MicroBitImage::MicroBitImage(const MicroBitImage &image)
|
||||
{
|
||||
bitmap = image.bitmap;
|
||||
width = image.width;
|
||||
height = image.height;
|
||||
ref = image.ref;
|
||||
|
||||
(*ref)++;
|
||||
ptr = image.ptr;
|
||||
ptr->incr();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -138,17 +136,12 @@ MicroBitImage::MicroBitImage(const char *s)
|
|||
parseReadPtr++;
|
||||
}
|
||||
|
||||
// Store the geomtery.
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->bitmap = (uint8_t *) malloc(width * height);
|
||||
this->ref = (int16_t *) malloc(sizeof(int16_t));
|
||||
*ref = 1;
|
||||
this->init(width, height, NULL);
|
||||
|
||||
// Second pass: collect the data.
|
||||
parseReadPtr = s;
|
||||
parseWritePtr = parseBuf;
|
||||
bitmapPtr = this->bitmap;
|
||||
bitmapPtr = this->getBitmap();
|
||||
|
||||
while (*parseReadPtr)
|
||||
{
|
||||
|
@ -172,6 +165,36 @@ MicroBitImage::MicroBitImage(const char *s)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create an image from a specially prepared constant array, with no copying. Will call ptr->incr().
|
||||
*
|
||||
* @param ptr The literal - first two bytes should be 0xff, then width, 0, height, 0, and the bitmap. Width and height are 16 bit. The literal has to be 4-byte aligned.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* static const uint8_t heart[] __attribute__ ((aligned (4))) = { 0xff, 0xff, 10, 0, 5, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
|
||||
* MicroBitImage i((ImageData*)(void*)heart);
|
||||
* @endcode
|
||||
*/
|
||||
MicroBitImage::MicroBitImage(ImageData *p)
|
||||
{
|
||||
ptr = p;
|
||||
ptr->incr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current ptr, do not decr() it, and set the current instance to empty image.
|
||||
* This is to be used by specialized runtimes which pass ImageData around.
|
||||
*/
|
||||
ImageData *MicroBitImage::leakData()
|
||||
{
|
||||
ImageData* res = ptr;
|
||||
init_empty();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a bitmap representation of a given size, based on a given buffer.
|
||||
|
@ -197,11 +220,7 @@ MicroBitImage::MicroBitImage(const int16_t x, const int16_t y, const uint8_t *bi
|
|||
*/
|
||||
MicroBitImage::~MicroBitImage()
|
||||
{
|
||||
if(--(*ref) == 0)
|
||||
{
|
||||
free(bitmap);
|
||||
free(ref);
|
||||
}
|
||||
ptr->decr();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,12 +228,7 @@ MicroBitImage::~MicroBitImage()
|
|||
*/
|
||||
void MicroBitImage::init_empty()
|
||||
{
|
||||
bitmap = MicroBitImage::EmptyImage.bitmap;
|
||||
width = MicroBitImage::EmptyImage.width;
|
||||
height = MicroBitImage::EmptyImage.height;
|
||||
ref = MicroBitImage::EmptyImage.ref;
|
||||
|
||||
(*ref)++;
|
||||
ptr = (ImageData*)(void*)empty;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -232,23 +246,21 @@ void MicroBitImage::init(const int16_t x, const int16_t y, const uint8_t *bitmap
|
|||
init_empty();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create a copy of the array
|
||||
this->width = x;
|
||||
this->height = y;
|
||||
ptr = (ImageData*)malloc(4 + x * y);
|
||||
ptr->init();
|
||||
ptr->width = x;
|
||||
ptr->height = y;
|
||||
|
||||
// create a linear buffer to represent the image. We could use a jagged/2D array here, but experimentation
|
||||
// showed this had a negative effect on memory management (heap fragmentation etc).
|
||||
|
||||
this->bitmap = (uint8_t *) malloc(width*height);
|
||||
|
||||
if (bitmap)
|
||||
this->printImage(x,y,bitmap);
|
||||
else
|
||||
this->clear();
|
||||
|
||||
ref = (int16_t *) malloc(sizeof(int16_t));
|
||||
*ref = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -271,21 +283,12 @@ void MicroBitImage::init(const int16_t x, const int16_t y, const uint8_t *bitmap
|
|||
*/
|
||||
MicroBitImage& MicroBitImage::operator = (const MicroBitImage& i)
|
||||
{
|
||||
if(this == &i)
|
||||
if(ptr == i.ptr)
|
||||
return *this;
|
||||
|
||||
if(--(*ref) == 0)
|
||||
{
|
||||
free(bitmap);
|
||||
free(ref);
|
||||
}
|
||||
|
||||
bitmap = i.bitmap;
|
||||
width = i.width;
|
||||
height = i.height;
|
||||
ref = i.ref;
|
||||
|
||||
(*ref)++;
|
||||
ptr->decr();
|
||||
ptr = i.ptr;
|
||||
ptr->incr();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -309,10 +312,10 @@ MicroBitImage& MicroBitImage::operator = (const MicroBitImage& i)
|
|||
*/
|
||||
bool MicroBitImage::operator== (const MicroBitImage& i)
|
||||
{
|
||||
if (bitmap == i.bitmap)
|
||||
if (ptr == i.ptr)
|
||||
return true;
|
||||
else
|
||||
return ((width == i.width) && (height == i.height) && (memcmp(bitmap, i.bitmap,width*height)==0));
|
||||
return (ptr->width == i.ptr->width && ptr->height == i.ptr->height && (memcmp(getBitmap(), i.ptr->data, getSize())==0));
|
||||
}
|
||||
|
||||
|
||||
|
@ -327,7 +330,7 @@ bool MicroBitImage::operator== (const MicroBitImage& i)
|
|||
*/
|
||||
void MicroBitImage::clear()
|
||||
{
|
||||
memclr(this->bitmap, width*height);
|
||||
memclr(getBitmap(), getSize());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -346,10 +349,10 @@ void MicroBitImage::clear()
|
|||
int MicroBitImage::setPixelValue(int16_t x , int16_t y, uint8_t value)
|
||||
{
|
||||
//sanity check
|
||||
if(x >= width || y >= height || x < 0 || y < 0)
|
||||
if(x >= getWidth() || y >= getHeight() || x < 0 || y < 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
this->bitmap[y*width+x] = value;
|
||||
this->getBitmap()[y*getWidth()+x] = value;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
@ -369,10 +372,10 @@ int MicroBitImage::setPixelValue(int16_t x , int16_t y, uint8_t value)
|
|||
int MicroBitImage::getPixelValue(int16_t x , int16_t y)
|
||||
{
|
||||
//sanity check
|
||||
if(x >= width || y >= height || x < 0 || y < 0)
|
||||
if(x >= getWidth() || y >= getHeight() || x < 0 || y < 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
return this->bitmap[y*width+x];
|
||||
return this->getBitmap()[y*getWidth()+x];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -403,18 +406,18 @@ int MicroBitImage::printImage(int16_t width, int16_t height, const uint8_t *bitm
|
|||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// Calcualte sane start pointer.
|
||||
pixelsToCopyX = min(width,this->width);
|
||||
pixelsToCopyY = min(height,this->height);
|
||||
pixelsToCopyX = min(width,this->getWidth());
|
||||
pixelsToCopyY = min(height,this->getHeight());
|
||||
|
||||
pIn = bitmap;
|
||||
pOut = this->bitmap;
|
||||
pOut = this->getBitmap();
|
||||
|
||||
// Copy the image, stride by stride.
|
||||
for (int i=0; i<pixelsToCopyY; i++)
|
||||
{
|
||||
memcpy(pOut, pIn, pixelsToCopyX);
|
||||
pIn += width;
|
||||
pOut += this->width;
|
||||
pOut += this->getWidth();
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
|
@ -445,21 +448,21 @@ int MicroBitImage::paste(const MicroBitImage &image, int16_t x, int16_t y, uint8
|
|||
|
||||
// Sanity check.
|
||||
// We permit writes that overlap us, but ones that are clearly out of scope we can filter early.
|
||||
if (x >= width || y >= height || x+image.width <= 0 || y+image.height <= 0)
|
||||
if (x >= getWidth() || y >= getHeight() || x+image.getWidth() <= 0 || y+image.getHeight() <= 0)
|
||||
return 0;
|
||||
|
||||
//Calculate the number of byte we need to copy in each dimension.
|
||||
cx = x < 0 ? min(image.width + x, width) : min(image.width, width - x);
|
||||
cy = y < 0 ? min(image.height + y, height) : min(image.height, height - y);
|
||||
cx = x < 0 ? min(image.getWidth() + x, getWidth()) : min(image.getWidth(), getWidth() - x);
|
||||
cy = y < 0 ? min(image.getHeight() + y, getHeight()) : min(image.getHeight(), getHeight() - y);
|
||||
|
||||
// Calculate sane start pointer.
|
||||
pIn = image.bitmap;
|
||||
pIn = image.ptr->data;
|
||||
pIn += (x < 0) ? -x : 0;
|
||||
pIn += (y < 0) ? -image.width*y : 0;
|
||||
pIn += (y < 0) ? -image.getWidth()*y : 0;
|
||||
|
||||
pOut = bitmap;
|
||||
pOut = getBitmap();
|
||||
pOut += (x > 0) ? x : 0;
|
||||
pOut += (y > 0) ? width*y : 0;
|
||||
pOut += (y > 0) ? getWidth()*y : 0;
|
||||
|
||||
// Copy the image, stride by stride
|
||||
// If we want primitive transparecy, we do this byte by byte.
|
||||
|
@ -478,8 +481,8 @@ int MicroBitImage::paste(const MicroBitImage &image, int16_t x, int16_t y, uint8
|
|||
}
|
||||
}
|
||||
|
||||
pIn += image.width;
|
||||
pOut += width;
|
||||
pIn += image.getWidth();
|
||||
pOut += getWidth();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -489,8 +492,8 @@ int MicroBitImage::paste(const MicroBitImage &image, int16_t x, int16_t y, uint8
|
|||
memcpy(pOut, pIn, cx);
|
||||
|
||||
pxWritten += cx;
|
||||
pIn += image.width;
|
||||
pOut += width;
|
||||
pIn += image.getWidth();
|
||||
pOut += getWidth();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -519,7 +522,7 @@ int MicroBitImage::print(char c, int16_t x, int16_t y)
|
|||
MicroBitFont font = uBit.display.getFont();
|
||||
|
||||
// Sanity check. Silently ignore anything out of bounds.
|
||||
if (x >= width || y >= height || c < MICROBIT_FONT_ASCII_START || c > font.asciiEnd)
|
||||
if (x >= getWidth() || y >= getHeight() || c < MICROBIT_FONT_ASCII_START || c > font.asciiEnd)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// Paste.
|
||||
|
@ -539,8 +542,8 @@ int MicroBitImage::print(char c, int16_t x, int16_t y)
|
|||
// Update our X co-ord write position
|
||||
x1 = x+col;
|
||||
|
||||
if (x1 < width && y1 < height)
|
||||
this->bitmap[y1*width+x1] = (v & (0x10 >> col)) ? 255 : 0;
|
||||
if (x1 < getWidth() && y1 < getHeight())
|
||||
this->getBitmap()[y1*getWidth()+x1] = (v & (0x10 >> col)) ? 255 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,24 +566,24 @@ int MicroBitImage::print(char c, int16_t x, int16_t y)
|
|||
*/
|
||||
int MicroBitImage::shiftLeft(int16_t n)
|
||||
{
|
||||
uint8_t *p = bitmap;
|
||||
int pixels = width-n;
|
||||
uint8_t *p = getBitmap();
|
||||
int pixels = getWidth()-n;
|
||||
|
||||
if (n <= 0 )
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if(n >= width)
|
||||
if(n >= getWidth())
|
||||
{
|
||||
clear();
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int y = 0; y < getHeight(); y++)
|
||||
{
|
||||
// Copy, and blank fill the rightmost column.
|
||||
memcpy(p, p+n, pixels);
|
||||
memclr(p+pixels, n);
|
||||
p += width;
|
||||
p += getWidth();
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
|
@ -602,24 +605,24 @@ int MicroBitImage::shiftLeft(int16_t n)
|
|||
*/
|
||||
int MicroBitImage::shiftRight(int16_t n)
|
||||
{
|
||||
uint8_t *p = bitmap;
|
||||
int pixels = width-n;
|
||||
uint8_t *p = getBitmap();
|
||||
int pixels = getWidth()-n;
|
||||
|
||||
if (n <= 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if(n >= width)
|
||||
if(n >= getWidth())
|
||||
{
|
||||
clear();
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int y = 0; y < getHeight(); y++)
|
||||
{
|
||||
// Copy, and blank fill the leftmost column.
|
||||
memmove(p+n, p, pixels);
|
||||
memclr(p, n);
|
||||
p += width;
|
||||
p += getWidth();
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
|
@ -646,25 +649,25 @@ int MicroBitImage::shiftUp(int16_t n)
|
|||
if (n <= 0 )
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if(n >= height)
|
||||
if(n >= getHeight())
|
||||
{
|
||||
clear();
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
pOut = bitmap;
|
||||
pIn = bitmap+width*n;
|
||||
pOut = getBitmap();
|
||||
pIn = getBitmap()+getWidth()*n;
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int y = 0; y < getHeight(); y++)
|
||||
{
|
||||
// Copy, and blank fill the leftmost column.
|
||||
if (y < height-n)
|
||||
memcpy(pOut, pIn, width);
|
||||
if (y < getHeight()-n)
|
||||
memcpy(pOut, pIn, getWidth());
|
||||
else
|
||||
memclr(pOut, width);
|
||||
memclr(pOut, getWidth());
|
||||
|
||||
pIn += width;
|
||||
pOut += width;
|
||||
pIn += getWidth();
|
||||
pOut += getWidth();
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
|
@ -691,63 +694,30 @@ int MicroBitImage::shiftDown(int16_t n)
|
|||
if (n <= 0 )
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if(n >= height)
|
||||
if(n >= getHeight())
|
||||
{
|
||||
clear();
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
pOut = bitmap + width*(height-1);
|
||||
pIn = pOut - width*n;
|
||||
pOut = getBitmap() + getWidth()*(getHeight()-1);
|
||||
pIn = pOut - getWidth()*n;
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int y = 0; y < getHeight(); y++)
|
||||
{
|
||||
// Copy, and blank fill the leftmost column.
|
||||
if (y < height-n)
|
||||
memcpy(pOut, pIn, width);
|
||||
if (y < getHeight()-n)
|
||||
memcpy(pOut, pIn, getWidth());
|
||||
else
|
||||
memclr(pOut, width);
|
||||
memclr(pOut, getWidth());
|
||||
|
||||
pIn -= width;
|
||||
pOut -= width;
|
||||
pIn -= getWidth();
|
||||
pOut -= getWidth();
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the width of this image.
|
||||
*
|
||||
* @return The width of this image.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
|
||||
* MicroBitImage i(10,5,heart);
|
||||
* i.getWidth(); //equals 10...
|
||||
* @endcode
|
||||
*/
|
||||
int MicroBitImage::getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the height of this image.
|
||||
*
|
||||
* @return The height of this image.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart
|
||||
* MicroBitImage i(10,5,heart);
|
||||
* i.getHeight(); //equals 5...
|
||||
* @endcode
|
||||
*/
|
||||
int MicroBitImage::getHeight()
|
||||
{
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the bitmap to a csv string.
|
||||
|
@ -762,14 +732,14 @@ int MicroBitImage::getHeight()
|
|||
ManagedString MicroBitImage::toString()
|
||||
{
|
||||
//width including commans and \n * height
|
||||
int stringSize = ((width * 2) * height);
|
||||
int stringSize = getSize() * 2;
|
||||
|
||||
//plus one for string terminator
|
||||
char parseBuffer[stringSize + 1];
|
||||
|
||||
parseBuffer[stringSize] = '\0';
|
||||
|
||||
uint8_t *bitmapPtr = bitmap;
|
||||
uint8_t *bitmapPtr = getBitmap();
|
||||
|
||||
int parseIndex = 0;
|
||||
int widthCount = 0;
|
||||
|
@ -783,7 +753,7 @@ ManagedString MicroBitImage::toString()
|
|||
|
||||
parseIndex++;
|
||||
|
||||
if(widthCount == width-1)
|
||||
if(widthCount == getWidth()-1)
|
||||
{
|
||||
parseBuffer[parseIndex] = '\n';
|
||||
widthCount = 0;
|
||||
|
@ -821,17 +791,17 @@ MicroBitImage MicroBitImage::crop(int startx, int starty, int cropWidth, int cro
|
|||
int newWidth = startx + cropWidth;
|
||||
int newHeight = starty + cropHeight;
|
||||
|
||||
if (newWidth >= width || newWidth <=0)
|
||||
newWidth = width;
|
||||
if (newWidth >= getWidth() || newWidth <=0)
|
||||
newWidth = getWidth();
|
||||
|
||||
if (newHeight >= height || newHeight <= 0)
|
||||
newHeight = height;
|
||||
if (newHeight >= getHeight() || newHeight <= 0)
|
||||
newHeight = getHeight();
|
||||
|
||||
//allocate our storage.
|
||||
uint8_t cropped[newWidth * newHeight];
|
||||
|
||||
//calculate the pointer to where we want to begin cropping
|
||||
uint8_t *copyPointer = bitmap + (width * starty) + startx;
|
||||
uint8_t *copyPointer = getBitmap() + (getWidth() * starty) + startx;
|
||||
|
||||
//get a reference to our storage
|
||||
uint8_t *pastePointer = cropped;
|
||||
|
@ -841,9 +811,27 @@ MicroBitImage MicroBitImage::crop(int startx, int starty, int cropWidth, int cro
|
|||
{
|
||||
memcpy(pastePointer, copyPointer, newWidth);
|
||||
|
||||
copyPointer += width;
|
||||
copyPointer += getWidth();
|
||||
pastePointer += newHeight;
|
||||
}
|
||||
|
||||
return MicroBitImage(newWidth, newHeight, cropped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if image is read-only (i.e., residing in flash).
|
||||
*/
|
||||
bool MicroBitImage::isReadOnly()
|
||||
{
|
||||
return ptr->isReadOnly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of the image bitmap. Used particularly, when isReadOnly() is true.
|
||||
*
|
||||
* @return an instance of MicroBitImage which can be modified independently of the current instance
|
||||
*/
|
||||
MicroBitImage MicroBitImage::clone()
|
||||
{
|
||||
return MicroBitImage(getWidth(), getHeight(), getBitmap());
|
||||
}
|
||||
|
|
46
source/RefCounted.cpp
Normal file
46
source/RefCounted.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include "mbed.h"
|
||||
#include "MicroBit.h"
|
||||
|
||||
void RefCounted::init()
|
||||
{
|
||||
// Initialize to one reference (lowest bit set to 1)
|
||||
refCount = 3;
|
||||
}
|
||||
|
||||
static inline bool isReadOnlyInline(RefCounted *t)
|
||||
{
|
||||
uint32_t refCount = t->refCount;
|
||||
|
||||
if (refCount == 0xffff)
|
||||
return true; // object in flash
|
||||
|
||||
// Do some sanity checking while we're here
|
||||
if (refCount == 1 || // object should have been deleted
|
||||
(refCount & 1) == 0) // refCount doesn't look right
|
||||
uBit.panic(MICROBIT_HEAP_ERROR);
|
||||
|
||||
// Not read only
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RefCounted::isReadOnly()
|
||||
{
|
||||
return isReadOnlyInline(this);
|
||||
}
|
||||
|
||||
void RefCounted::incr()
|
||||
{
|
||||
if (!isReadOnlyInline(this))
|
||||
refCount += 2;
|
||||
}
|
||||
|
||||
void RefCounted::decr()
|
||||
{
|
||||
if (isReadOnlyInline(this))
|
||||
return;
|
||||
|
||||
refCount -= 2;
|
||||
if (refCount == 1) {
|
||||
free(this);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue