corinthia-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pmke...@apache.org
Subject [1/4] incubator-corinthia git commit: Add Objective C framework code from UX Write
Date Wed, 19 Aug 2015 15:38:18 GMT
Repository: incubator-corinthia
Updated Branches:
  refs/heads/master 5202fbf16 -> 9f851a342


http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDSaveOperation.h
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDSaveOperation.h b/experiments/objcFramework/EDSaveOperation.h
new file mode 100644
index 0000000..944aedc
--- /dev/null
+++ b/experiments/objcFramework/EDSaveOperation.h
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import <FileClient/FCOperation.h>
+
+@class EDEditor;
+
+typedef void (^EDSaveCompletion)(BOOL cancelled, NSError *error);
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                         EDSaveOperation                                        //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDSaveOperation : FCOperation
+
+@property (assign, readonly) NSUInteger completionCount;
+
+- (EDSaveOperation *)initWithEditor:(EDEditor *)editor path:(NSString *)path;
+- (void)addCompletion:(EDSaveCompletion)completion;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDSaveOperation.m
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDSaveOperation.m b/experiments/objcFramework/EDSaveOperation.m
new file mode 100644
index 0000000..b5f65ba
--- /dev/null
+++ b/experiments/objcFramework/EDSaveOperation.m
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import "EDSaveOperation.h"
+#import "EDEditor.h"
+#import "EDJSInterface.h"
+#import "EDTiming.h"
+#import "EDFileFormat.h"
+#import <FileClient/FCError.h>
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                         EDSaveOperation                                        //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation EDSaveOperation
+{
+    EDEditor *_editor;
+    NSString *_path;
+    NSMutableArray *_completions;
+}
+
+- (EDSaveOperation *)initWithEditor:(EDEditor *)editor path:(NSString *)path
+{
+    if (!(self = [super init]))
+        return nil;
+    _editor = editor;
+    _path = [path copy];
+    _completions = [NSMutableArray arrayWithCapacity: 0];
+    return self;
+}
+
+- (NSUInteger)completionCount
+{
+    return _completions.count;
+}
+
+- (void)addCompletion:(EDSaveCompletion)completion;
+{
+    [_completions addObject: [completion copy]];
+}
+
+- (void)start
+{
+    [super start];
+
+    assert(self == _editor.activeSave);
+    _editor.delegate.editorIsSaving = YES;
+    // Start the actual save in a separate iteration of the event loop, so that the "Saving" label
+    // and animated activity indicator become visible
+    [self performSelector: @selector(stage1) withObject: nil afterDelay: 0];
+}
+
+- (void)stage1
+{
+    if (!_editor.js.documentModified) {
+        [self succeed: nil];
+        return;
+    }
+
+    NSFileManager *fm = [NSFileManager defaultManager];
+    NSString *tempPath = [NSString stringWithFormat: @"%@.saving", _path];
+    [_editor.saveTiming start];
+
+    if (![_editor.js.main prepareForSave]) {
+        [self fail: [NSError error: @"JS prepareForSave failed"]];
+        return;
+    }
+    [_editor.saveTiming addEntry: @"JS prepare for save"];
+    NSString *html = [_editor.js.main getHTML];
+
+    // Save the document to a temporary file (so if it fails, we still have the original)
+    [_editor.fileFormat save: tempPath html: html completion:^(NSError *error) {
+        if (error != nil) {
+            [self fail: error];
+            return;
+        }
+
+        // Delete temp dir
+        error = nil;
+        if ([fm fileExistsAtPath: _editor.tempDir] && ![fm removeItemAtPath: _editor.tempDir error: &error]) {
+            [self fail: error];
+            return;
+        }
+
+        // Check if the file has actually changed - if not, avoid trigering an upload and updating the
+        // modification time
+        if ([fm contentsEqualAtPath: tempPath andPath: _path]) {
+            [fm removeItemAtPath: tempPath error: nil];
+            [self succeed: nil];
+            return;
+        }
+
+        // Remove old version of file
+        if ([fm fileExistsAtPath: _path] && ![fm removeItemAtPath: _path error: &error]) {
+            [self fail: error];
+            return;
+        }
+
+        // Rename temporary file
+        if (![fm moveItemAtPath: tempPath toPath: _path error: &error]) {
+            [self fail: error];
+            return;
+        }
+
+        // Save succsesful. Tell the sync manager to start uploading the file (if it's on a remote
+        // server), and to do so even if the app is in the background
+        _editor.js.documentModified = NO;
+        [_editor.delegate editorDidSaveFile];
+        [_editor.saveTiming addEntry: @"Completed save"];
+        [self succeed: nil];
+    }];
+}
+
+- (void)cleanup
+{
+    for (EDSaveCompletion completion in _completions) {
+        if (self.status == FCOperationStatusCancelled)
+            completion(YES,nil);
+        else if (self.status == FCOperationStatusFailed)
+            completion(NO,self.privateError);
+        else
+            completion(NO,nil);
+    }
+    _completions = nil; // break retain cycles
+
+    _editor.delegate.editorIsSaving = NO;
+
+    assert(self == _editor.activeSave);
+
+    if (_editor.pendingSave != nil) {
+        _editor.activeSave = _editor.pendingSave;
+        _editor.pendingSave = nil;
+        [_editor.activeSave start];
+    }
+    else {
+        _editor.activeSave = nil;
+    }
+
+    assert(self != _editor.activeSave);
+    [_editor debugSaveStatus];
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDScan.h
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDScan.h b/experiments/objcFramework/EDScan.h
new file mode 100644
index 0000000..0ef58d3
--- /dev/null
+++ b/experiments/objcFramework/EDScan.h
@@ -0,0 +1,64 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import <FileClient/FCOperation.h>
+
+@class EDEditor;
+@class EDScanResults;
+@class EDScanResultsSection;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                         EDScanParagraph                                        //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDScanParagraph : NSObject
+
+@property (copy, readonly) NSString *text;
+@property (copy, readonly) NSString *sectionId;
+
+- (EDScanParagraph *)initWithText:(NSString *)text sectionId:(NSString *)sectionId;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                         EDScanOperation                                        //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDScanOperation : FCOperation
+
+@property (weak, readonly) EDEditor *editor;
+@property (strong, readonly) EDScanResults *results;
+@property (strong) EDScanResultsSection *currentSection;
+@property (strong, readonly) NSString *lastSectionId;
+
+- (EDScanOperation *)initWithEditor:(EDEditor *)editor;
+- (void)includeCurrentSection;
+- (void)processParagraph:(EDScanParagraph *)paragraph;
+- (void)foundMatches:(NSArray *)newMatches;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDScan.m
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDScan.m b/experiments/objcFramework/EDScan.m
new file mode 100644
index 0000000..9353f7c
--- /dev/null
+++ b/experiments/objcFramework/EDScan.m
@@ -0,0 +1,138 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import "EDScan.h"
+#import "EDScanResults.h"
+#import "EDEditor.h"
+#import "EDJSInterface.h"
+#import "EDOutline.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                         EDScanParagraph                                        //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation EDScanParagraph
+
+- (EDScanParagraph *)initWithText:(NSString *)text sectionId:(NSString *)sectionId
+{
+    if (!(self = [super init]))
+        return nil;
+    _text = [text copy];
+    _sectionId = [sectionId copy];
+    return self;
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                         EDScanOperation                                        //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation EDScanOperation
+{
+    BOOL _cancelled;
+}
+
+- (EDScanOperation *)initWithEditor:(EDEditor *)editor
+{
+    if (!(self = [super init]))
+        return nil;
+    _editor = editor;
+    _results = [[EDScanResults alloc] init];
+    return self;
+}
+
+- (void)start
+{
+    [super start];
+
+    [_editor.js.scan reset];
+    [self performSelector: @selector(next) withObject: nil afterDelay: 0.1];
+}
+
+- (void)cancel
+{
+    _cancelled = YES;
+    [super cancel];
+}
+
+- (void)next
+{
+    if (self.status != FCOperationStatusActive)
+        return;
+
+    EDScanParagraph *paragraph = [_editor.js.scan next];
+    if (paragraph == nil) {
+        [self succeed: nil];
+        return;
+    }
+    else {
+        if (paragraph.sectionId != nil) {
+            _lastSectionId = paragraph.sectionId;
+            _currentSection = nil;
+        }
+
+        [self processParagraph: paragraph];
+        [self performSelector: @selector(next) withObject: nil afterDelay: 0];
+    }
+}
+
+- (void)includeCurrentSection
+{
+    if (_currentSection == nil) {
+        EDOutlineItem *item = nil;
+        if (_lastSectionId != nil)
+            item = [_editor.outline lookupItem: _lastSectionId];
+        if (item != nil)
+            _currentSection = [[EDScanResultsSection alloc] initWithTitle: item.title];
+        else
+            _currentSection = [[EDScanResultsSection alloc] initWithTitle: nil];
+        [_results.sections addObject: _currentSection];
+    }
+}
+
+- (void)processParagraph:(EDScanParagraph *)paragraph
+{
+    // Default implementation does nothing
+}
+
+- (void)foundMatches:(NSArray *)newMatches
+{
+    for (EDScanMatch *match in newMatches)
+        [_editor.js.scan showMatch: match.matchId];
+
+    // We must add these *after* calling the JS showMatch method, as modifying the results will cause
+    // ScanMode to go to the first one if there were no previous matches, and this will modify the document
+    // structure, by adding a selection highlight around the match.
+    for (EDScanMatch *match in newMatches) {
+        [self.currentSection.matches addObject: match];
+        [self.results addMatch: match];
+    }
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDScanResults.h
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDScanResults.h b/experiments/objcFramework/EDScanResults.h
new file mode 100644
index 0000000..d9857b4
--- /dev/null
+++ b/experiments/objcFramework/EDScanResults.h
@@ -0,0 +1,73 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import <Foundation/Foundation.h>
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                           EDScanMatch                                          //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDScanMatch : NSObject
+
+@property (assign, readonly) int matchId;
+@property (copy, readonly) NSString *text;
+
+- (EDScanMatch *)initWithMatchId:(int)matchId text:(NSString *)text;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                      EDScanResultsSection                                      //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDScanResultsSection : NSObject
+
+@property (copy, readonly) NSString *title;
+@property (strong, readonly) NSMutableArray *matches;
+
+- (EDScanResultsSection *)initWithTitle:(NSString *)title;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                          EDScanResults                                         //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDScanResults : NSObject
+
+@property (readonly) NSMutableArray *sections;
+
+- (EDScanResults *)init;
+- (NSUInteger)matchCount;
+- (EDScanMatch *)matchAtIndex:(NSUInteger)index;
+- (void)addMatch:(EDScanMatch *)match;
+- (void)removeMatch:(EDScanMatch *)match;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDScanResults.m
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDScanResults.m b/experiments/objcFramework/EDScanResults.m
new file mode 100644
index 0000000..e5ed9f2
--- /dev/null
+++ b/experiments/objcFramework/EDScanResults.m
@@ -0,0 +1,109 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import "EDScanResults.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                           EDScanMatch                                          //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation EDScanMatch
+
+- (EDScanMatch *)initWithMatchId:(int)matchId text:(NSString *)text
+{
+    if (!(self = [super init]))
+        return nil;
+    _matchId = matchId;
+    _text = [text copy];
+    return self;
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                      EDScanResultsSection                                      //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation EDScanResultsSection
+
+- (EDScanResultsSection *)initWithTitle:(NSString *)title
+{
+    if (!(self = [super init]))
+        return nil;
+    _title = [title copy];
+    _matches = [NSMutableArray arrayWithCapacity: 0];
+    return self;
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                          EDScanResults                                         //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation EDScanResults
+{
+    NSMutableArray *_allMatches;
+}
+
+- (EDScanResults *)init
+{
+    if (!(self = [super init]))
+        return nil;
+    _sections = [NSMutableArray arrayWithCapacity: 0];
+    _allMatches = [NSMutableArray arrayWithCapacity: 0];
+    return self;
+}
+
+- (NSUInteger)matchCount
+{
+    return _allMatches.count;
+}
+
+- (EDScanMatch *)matchAtIndex:(NSUInteger)index
+{
+    return [_allMatches objectAtIndex: index];
+}
+
+- (void)addMatch:(EDScanMatch *)match
+{
+    [self willChangeValueForKey: @"matchCount"];
+    [_allMatches addObject: match];
+    [self didChangeValueForKey: @"matchCount"];
+}
+
+- (void)removeMatch:(EDScanMatch *)match
+{
+    [self willChangeValueForKey: @"matchCount"];
+    [_allMatches removeObject: match];
+    [self didChangeValueForKey: @"matchCount"];
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDSelectionFormatting.h
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDSelectionFormatting.h b/experiments/objcFramework/EDSelectionFormatting.h
new file mode 100644
index 0000000..27dc82d
--- /dev/null
+++ b/experiments/objcFramework/EDSelectionFormatting.h
@@ -0,0 +1,55 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import <Foundation/Foundation.h>
+#import <Editor/DocFormats.h>
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                      EDSelectionFormatting                                     //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDSelectionFormatting : NSObject
+
+@property (assign, readonly) CSSProperties *cssProperties;
+
+@property (assign, readonly) BOOL shift;
+@property (assign, readonly) BOOL inBrackets;
+@property (assign, readonly) BOOL inQuotes;
+@property (assign, readonly) BOOL inImage;
+@property (assign, readonly) BOOL inFigure;
+@property (assign, readonly) BOOL inTable;
+@property (assign, readonly) BOOL inReference;
+@property (assign, readonly) BOOL inLink;
+@property (assign, readonly) BOOL inTOC;
+@property (assign, readonly) BOOL inUL;
+@property (assign, readonly) BOOL inOL;
+@property (assign, readonly) BOOL inTT;
+@property (assign, readonly) NSString *inItemTitle;
+
+- (EDSelectionFormatting *)init;
+- (EDSelectionFormatting *)initWithProperties:(NSDictionary *)properties;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDSelectionFormatting.m
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDSelectionFormatting.m b/experiments/objcFramework/EDSelectionFormatting.m
new file mode 100644
index 0000000..1bffa5f
--- /dev/null
+++ b/experiments/objcFramework/EDSelectionFormatting.m
@@ -0,0 +1,73 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import "EDSelectionFormatting.h"
+#import "EDUtil.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                      EDSelectionFormatting                                     //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation EDSelectionFormatting
+
+- (EDSelectionFormatting *)init
+{
+    return [self initWithProperties: @{ }];
+}
+
+- (EDSelectionFormatting *)initWithProperties:(NSDictionary *)properties
+{
+    if (!(self = [super init]))
+        return nil;
+    _cssProperties = CSSPropertiesNew();
+
+    DFHashTable *hashTable = HashTableFromNSDictionary(properties);
+    CSSPropertiesUpdateFromRaw(_cssProperties,hashTable);
+    DFHashTableRelease(hashTable);
+
+    return self;
+}
+
+- (void)dealloc
+{
+    CSSPropertiesRelease(_cssProperties);
+}
+
+- (BOOL)shift { return DFStringEquals("true",CSSGet(_cssProperties,"-uxwrite-shift")); }
+- (BOOL)inBrackets { return DFStringEquals("true",CSSGet(_cssProperties,"-uxwrite-in-brackets")); }
+- (BOOL)inQuotes { return DFStringEquals("true",CSSGet(_cssProperties,"-uxwrite-in-quotes")); }
+- (BOOL)inImage { return DFStringEquals("true",CSSGet(_cssProperties,"-uxwrite-in-image")); }
+- (BOOL)inFigure { return DFStringEquals("true",CSSGet(_cssProperties,"-uxwrite-in-figure")); }
+- (BOOL)inTable { return DFStringEquals("true",CSSGet(_cssProperties,"-uxwrite-in-table")); }
+- (BOOL)inReference { return DFStringEquals("true",CSSGet(_cssProperties,"-uxwrite-in-reference")); }
+- (BOOL)inLink { return DFStringEquals("true",CSSGet(_cssProperties,"-uxwrite-in-link")); }
+- (BOOL)inTOC { return DFStringEquals("true",CSSGet(_cssProperties,"-uxwrite-in-toc")); }
+- (BOOL)inUL { return DFStringEquals("true",CSSGet(_cssProperties,"-uxwrite-in-ul")); }
+- (BOOL)inOL { return DFStringEquals("true",CSSGet(_cssProperties,"-uxwrite-in-ol")); }
+- (BOOL)inTT { return DFStringEquals("true",CSSGet(_cssProperties,"-uxwrite-in-tt")); }
+- (NSString *)inItemTitle { return NSStringFromC(CSSGet(_cssProperties,"-uxwrite-in-item-title")); }
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDStyle.h
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDStyle.h b/experiments/objcFramework/EDStyle.h
new file mode 100644
index 0000000..f71e096
--- /dev/null
+++ b/experiments/objcFramework/EDStyle.h
@@ -0,0 +1,59 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import <Foundation/Foundation.h>
+#import <Editor/DocFormats.h>
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                             EDStyle                                            //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDStyle : NSObject
+
+@property (readonly) CSSStyle *cssStyle;
+
++ (EDStyle *)styleWithCSSStyle:(CSSStyle *)cssStyle;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                            EDCascade                                           //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDCascade : NSObject
+
+@property (assign, readwrite, nonatomic) CSSProperties *defaultProperties;
+@property (assign, readwrite, nonatomic) CSSProperties *docProperties;
+@property (assign, readwrite, nonatomic) CSSProperties *styleProperties;
+@property (assign, readwrite, nonatomic) CSSProperties *directProperties;
+
+- (EDCascade *)init;
+- (NSString *)get:(NSString *)name;
+- (void)set:(NSString *)name value:(NSString *)value;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDStyle.m
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDStyle.m b/experiments/objcFramework/EDStyle.m
new file mode 100644
index 0000000..a45d7a9
--- /dev/null
+++ b/experiments/objcFramework/EDStyle.m
@@ -0,0 +1,150 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import "EDStyle.h"
+#import "EDUtil.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                             EDStyle                                            //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation EDStyle
+
+- (void)dealloc
+{
+    CSSStyleRelease(_cssStyle);
+}
+
+- (BOOL)isEqual:(id)object
+{
+    if ((object == nil) || ![object isKindOfClass: [EDStyle class]])
+        return NO;
+    EDStyle *otherStyle = (EDStyle *)object;
+    return (_cssStyle == otherStyle.cssStyle);
+}
+
++ (EDStyle *)styleWithCSSStyle:(CSSStyle *)cssStyle
+{
+    if (cssStyle == NULL)
+        return nil;
+    EDStyle *style = [[EDStyle alloc] init];
+    style->_cssStyle = CSSStyleRetain(cssStyle);
+    return style;
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                            EDCascade                                           //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation EDCascade
+
+- (EDCascade *)init
+{
+    if (!(self = [super init]))
+        return nil;
+    return self;
+}
+
+- (void)dealloc
+{
+    CSSPropertiesRelease(_defaultProperties);
+    CSSPropertiesRelease(_docProperties);
+    CSSPropertiesRelease(_styleProperties);
+    CSSPropertiesRelease(_directProperties);
+}
+
+- (void)setPropertiesPtr:(CSSProperties **)ptr value:(CSSProperties *)value
+{
+    if (*ptr != value) {
+        CSSPropertiesRelease(*ptr);
+        *ptr = CSSPropertiesRetain(value);
+    }
+}
+
+- (void)setDefaultProperties:(CSSProperties *)defaultProperties
+{
+    [self setPropertiesPtr: &_defaultProperties value: defaultProperties];
+}
+
+- (void)setDocProperties:(CSSProperties *)docProperties
+{
+    [self setPropertiesPtr: &_docProperties value: docProperties];
+}
+
+- (void)setStyleProperties:(CSSProperties *)styleProperties
+{
+    [self setPropertiesPtr: &_styleProperties value: styleProperties];
+}
+
+- (void)setDirectProperties:(CSSProperties *)directProperties
+{
+    [self setPropertiesPtr: &_directProperties value: directProperties];
+}
+
+- (NSString *)get:(NSString *)name includeDirect:(BOOL)includeDirect
+{
+    CSSProperties *cascade[4] = { _directProperties, _styleProperties, _docProperties, _defaultProperties };
+    size_t count = 4;
+    size_t first = includeDirect ? 0 : 1;
+    for (size_t i = first; i < count; i++) {
+        if (cascade[i] != NULL) {
+            const char *value = CSSGet(cascade[i],name.UTF8String);
+            if (value != NULL)
+                return [NSString stringWithUTF8String: value];
+        }
+    }
+    return nil;
+}
+
+- (NSString *)get:(NSString *)name
+{
+    return [self get: name includeDirect: YES];
+}
+
+- (void)set:(NSString *)name value:(NSString *)value
+{
+    if (_directProperties == NULL)
+        return;
+
+    // If the value is unchanged, don't call CSSPut; this avoids triggering an unnecessary change notification
+    NSString *oldValue = [self get: name includeDirect: YES];
+    if (EDStringEquals(oldValue,value))
+        return;
+
+    // If the value being set is the same as the value inherited from the style, document, or detauls, remove
+    // the direct formatting property. Otherwise, set it to override the inherited value.
+    NSString *parentValue = [self get: name includeDirect: NO];
+    if (EDStringEquals(parentValue,value))
+        CSSPut(_directProperties,name.UTF8String,NULL);
+    else
+        CSSPut(_directProperties,name.UTF8String,value.UTF8String);
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDTiming.h
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDTiming.h b/experiments/objcFramework/EDTiming.h
new file mode 100644
index 0000000..0dba3a9
--- /dev/null
+++ b/experiments/objcFramework/EDTiming.h
@@ -0,0 +1,80 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import <Foundation/Foundation.h>
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                          EDTimingEntry                                         //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDTimingEntry : NSObject
+
+@property (copy, readonly) NSString *name;
+@property (assign, readonly) NSTimeInterval time;
+@property (assign, readonly) NSTimeInterval min;
+@property (assign, readonly) NSTimeInterval max;
+
+- (EDTimingEntry *)initWithName:(NSString *)name time:(NSTimeInterval)time;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                          EDTimingInfo                                          //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDTimingInfo : NSObject
+
+@property (strong, readonly) NSArray *entries;
+@property (assign, readonly) NSTimeInterval total;
+
+- (EDTimingInfo *)init;
+- (void)start;
+- (void)addEntry:(NSString *)name;
+- (NSString *)descriptionWithTitle:(NSString *)title;
+- (NSString *)detailedDescription;
+
++ (EDTimingInfo *)computeAverages:(NSArray *)timings;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                         EDTimingRecords                                        //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDTimingRecords : NSObject
+
+@property (assign, readonly) NSUInteger max;
+@property (assign, readonly) NSUInteger count;
+@property (assign, readonly) NSTimeInterval average;
+
+- (EDTimingRecords *)initWithMax:(NSUInteger)max;
+- (void)add:(NSTimeInterval)interval;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDTiming.m
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDTiming.m b/experiments/objcFramework/EDTiming.m
new file mode 100644
index 0000000..5e7c675
--- /dev/null
+++ b/experiments/objcFramework/EDTiming.m
@@ -0,0 +1,271 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import "EDTiming.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                          EDTimingEntry                                         //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation EDTimingEntry
+
+- (EDTimingEntry *)initWithName:(NSString *)name
+                         time:(NSTimeInterval)time
+                          min:(NSTimeInterval)min
+                          max:(NSTimeInterval)max
+{
+    if (!(self = [super init]))
+        return nil;
+    _name = [name copy];
+    _time = time;
+    _min = min;
+    _max = max;
+    return self;
+}
+
+- (EDTimingEntry *)initWithName:(NSString *)name time:(NSTimeInterval)time
+{
+    return [self initWithName: name time: time min: time max: time];
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat: @"%@: %dms", _name, (int)(_time*1000)];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                          EDTimingInfo                                          //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDTimingInfo()
+
+@property (strong) NSDate *lastTime;
+
+@end
+
+@implementation EDTimingInfo
+{
+    NSMutableArray *_entries;
+}
+
+- (EDTimingInfo *)initWithEntries:(NSMutableArray *)entries
+{
+    if (!(self = [super init]))
+        return nil;
+    _entries = entries;
+    for (EDTimingEntry *entry in _entries)
+        _total += entry.time;
+    return self;
+}
+
+- (EDTimingInfo *)init
+{
+    return [self initWithEntries: [NSMutableArray arrayWithCapacity: 0]];
+}
+
+- (void)start
+{
+    [_entries removeAllObjects];
+    self.lastTime = [NSDate date];
+}
+
+- (void)addEntry:(NSString *)name
+{
+    if (self.lastTime == nil)
+        [self start];
+
+    NSDate *now = [NSDate date];
+    NSTimeInterval interval = [now timeIntervalSinceDate: self.lastTime];
+    self.lastTime = now;
+    [_entries addObject: [[EDTimingEntry alloc] initWithName: name time: interval]];
+    _total += interval;
+}
+
+- (NSString *)description
+{
+    NSMutableString *result = [NSMutableString stringWithCapacity: 0];
+    for (EDTimingEntry *entry in _entries)
+        [result appendFormat: @"%@\n", entry];
+    [result appendFormat: @"Total: %dms", (int)(_total*1000)];
+    return result;
+}
+
+- (NSString *)descriptionWithTitle:(NSString *)title
+{
+    NSMutableString *result = [NSMutableString stringWithCapacity: 0];
+    [result appendFormat: @"%@\n",title];
+    for (EDTimingEntry *entry in _entries)
+        [result appendFormat: @"    %@\n", entry];
+    [result appendFormat: @"    Total: %dms", (int)(_total*1000)];
+    return result;
+}
+
+- (NSString *)detailedDescription
+{
+    // Use UTF8 strings here, since field width specifiers don't seem to work with %@
+    NSMutableString *result = [NSMutableString stringWithCapacity: 0];
+    [result appendFormat: @"%-40s %-8s %-8s %-8s\n", "Stage", "Avg", "Min", "Max"];
+    [result appendFormat: @"%-40s %-8s %-8s %-8s\n", "-----", "---", "---", "---"];
+    for (EDTimingEntry *entry in _entries) {
+        [result appendFormat: @"%-40s %-8d %-8d %-8d\n",
+         entry.name.UTF8String,
+         (int)(entry.time*1000),
+         (int)(entry.min*1000),
+         (int)(entry.max*1000)];
+    }
+    [result appendFormat: @"Total: %dms", (int)(_total*1000)];
+    return result;
+}
+
+- (BOOL)hasSameEntryNamesAs:(EDTimingInfo *)other
+{
+    if (self.entries.count != other.entries.count)
+        return NO;
+    for (NSUInteger i = 0; i < self.entries.count; i++) {
+        EDTimingEntry *selfEntry = [self.entries objectAtIndex: i];
+        EDTimingEntry *otherEntry = [other.entries objectAtIndex: i];
+        if (![selfEntry.name isEqualToString: otherEntry.name])
+            return NO;
+    }
+    return YES;
+}
+
++ (EDTimingInfo *)computeAverages:(NSArray *)timings
+{
+    if (timings.count == 0)
+        return nil;
+    EDTimingInfo *first = [timings objectAtIndex: 0];
+
+    for (EDTimingInfo *current in timings) {
+        if (![current hasSameEntryNamesAs: first])
+            return nil;
+    }
+
+    NSUInteger numEntries = first.entries.count;
+
+    NSMutableArray *minArray = [NSMutableArray arrayWithCapacity: 0];
+    NSMutableArray *maxArray = [NSMutableArray arrayWithCapacity: 0];
+    NSMutableArray *totalArray = [NSMutableArray arrayWithCapacity: 0];
+    for (NSUInteger i = 0; i < numEntries; i++) {
+        [minArray addObject: [NSNumber numberWithDouble: 0]];
+        [maxArray addObject: [NSNumber numberWithDouble: 0]];
+        [totalArray addObject: [NSNumber numberWithDouble: 0]];
+    }
+
+    for (EDTimingInfo *current in timings) {
+        for (NSUInteger i = 0; i < current.entries.count; i++) {
+            EDTimingEntry *entry = [current.entries objectAtIndex: i];
+
+            NSNumber *minVal = [minArray objectAtIndex: i];
+            if ((current == first) || (minVal.doubleValue > entry.min)) {
+                minVal = [NSNumber numberWithDouble: entry.min];
+                [minArray replaceObjectAtIndex: i withObject: minVal];
+            }
+
+            NSNumber *maxVal = [maxArray objectAtIndex: i];
+            if ((current == first) || (maxVal.doubleValue < entry.max)) {
+                maxVal = [NSNumber numberWithDouble: entry.max];
+                [maxArray replaceObjectAtIndex: i withObject: maxVal];
+            }
+
+            NSNumber *totalVal = [totalArray objectAtIndex: i];
+            totalVal = [NSNumber numberWithDouble: totalVal.doubleValue + entry.time];
+            [totalArray replaceObjectAtIndex: i withObject: totalVal];
+        }
+    }
+
+    NSMutableArray *results = [NSMutableArray arrayWithCapacity: 0];
+    for (NSUInteger i = 0; i < first.entries.count; i++) {
+        EDTimingEntry *entry = [first.entries objectAtIndex: i];
+        NSNumber *minVal = [minArray objectAtIndex: i];
+        NSNumber *maxVal = [maxArray objectAtIndex: i];
+        NSNumber *totalVal = [totalArray objectAtIndex: i];
+        EDTimingEntry *combined = [[EDTimingEntry alloc] initWithName: entry.name
+                                                             time: totalVal.doubleValue/timings.count
+                                                              min: minVal.doubleValue
+                                                              max: maxVal.doubleValue];
+        [results addObject: combined];
+    }
+
+    return [[EDTimingInfo alloc] initWithEntries: results];
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                         EDTimingRecords                                        //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation EDTimingRecords
+{
+    NSTimeInterval *_values;
+}
+
+- (EDTimingRecords *)initWithMax:(NSUInteger)max
+{
+    if (!(self = [super init]))
+        return nil;
+    _max = max;
+    _count = 0;
+    _values = (NSTimeInterval *)malloc(_max*sizeof(NSTimeInterval));
+    return self;
+}
+
+- (void)dealloc
+{
+    free(_values);
+}
+
+- (void)add:(NSTimeInterval)interval
+{
+    if (_count == _max) {
+        for (NSUInteger i = 0; i < _max-1; i++)
+            _values[i] = _values[i+1];
+    }
+    else {
+        _count++;
+    }
+    _values[_count-1] = interval;
+}
+
+- (NSTimeInterval)average
+{
+    if (_count == 0)
+        return 0;
+
+    NSTimeInterval total = 0;
+    for (NSUInteger i = 0; i < _count; i++)
+        total += _values[i];
+    return total/_count;
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDUtil.h
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDUtil.h b/experiments/objcFramework/EDUtil.h
new file mode 100644
index 0000000..56c3606
--- /dev/null
+++ b/experiments/objcFramework/EDUtil.h
@@ -0,0 +1,41 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import <Foundation/Foundation.h>
+#import <Editor/DocFormats.h>
+
+extern int debugIndent;
+void debug(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
+DFHashTable *HashTableFromNSDictionary(NSDictionary *dict);
+NSDictionary *NSDictionaryFromHashTable(DFHashTable *hashTable);
+NSDictionary *NSDictionaryFromNestedHashTable(DFHashTable *outerHash);
+NSString *DFFixStringEncoding(NSString *str);
+NSString *NSStringFromC(const char *cstr);
+void NSErrorSetFromDFError(NSError **nserror, DFError *dferror);
+void DFErrorReleaseToNSError(DFError *dferror, NSError **nserror);
+void DFErrorSetFromNSError(DFError **dferror, NSError *nserror);
+
+BOOL EDStringEquals(NSString *a, NSString *b);
+NSString *EDEncodeFontFamily(NSString *input);
+NSString *EDDecodeFontFamily(NSString *input);

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDUtil.m
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDUtil.m b/experiments/objcFramework/EDUtil.m
new file mode 100644
index 0000000..127e407
--- /dev/null
+++ b/experiments/objcFramework/EDUtil.m
@@ -0,0 +1,325 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import "EDUtil.h"
+#import <FileClient/FCError.h>
+#include <iconv.h>
+
+int debugIndent = 0;
+
+void debug(NSString *format, ...)
+{
+    for (int i = 0; i < debugIndent; i++)
+        printf("    ");
+    va_list ap;
+    va_start(ap,format);
+    NSString *message = [[NSString alloc] initWithFormat: format arguments: ap];
+    va_end(ap);
+    printf("%s",message.UTF8String);
+}
+
+DFHashTable *HashTableFromNSDictionary(NSDictionary *dict)
+{
+    if (dict == NULL)
+        return NULL;
+
+    DFHashTable *hashTable = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
+    for (NSString *key in dict.allKeys) {
+        NSString *value = [dict objectForKey: key];
+        assert([value isKindOfClass: [NSString class]]);
+        DFHashTableAdd(hashTable,key.UTF8String,value.UTF8String);
+    }
+    return hashTable;
+}
+
+NSDictionary *NSDictionaryFromHashTable(DFHashTable *hashTable)
+{
+    if (hashTable == NULL)
+        return NULL;
+    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity: 0];
+    const char **keys = DFHashTableCopyKeys(hashTable);
+    for (int i = 0; keys[i]; i++) {
+        const char *key = keys[i];
+        const char *value = DFHashTableLookup(hashTable,key);
+        [dict setObject: NSStringFromC(value) forKey: NSStringFromC(key)];
+    }
+    free(keys);
+    return dict;
+}
+
+NSDictionary *NSDictionaryFromNestedHashTable(DFHashTable *outerHash)
+{
+    NSMutableDictionary *outerDict = [NSMutableDictionary dictionaryWithCapacity: 0];
+    const char **allOuterKeys = DFHashTableCopyKeys(outerHash);
+    for (int outerIndex = 0; allOuterKeys[outerIndex]; outerIndex++) {
+        const char *outerKey = allOuterKeys[outerIndex];
+        DFHashTable *innerHash = DFHashTableLookup(outerHash,outerKey);
+        assert(innerHash != NULL);
+        NSDictionary *innerDict = NSDictionaryFromHashTable(innerHash);
+        [outerDict setObject: innerDict forKey: NSStringFromC(outerKey)];
+    }
+    free(allOuterKeys);
+    return outerDict;
+}
+
+#define UTF16IsLeadSurrogate(_c)  (((_c) >= 0xD800) && ((_c) <= 0xDBFF))
+#define UTF16IsTrailSurrogate(_c) (((_c) >= 0xDC00) && ((_c) <= 0xDFFF))
+
+typedef struct DFUTF16Buffer DFUTF16Buffer;
+
+struct DFUTF16Buffer {
+    size_t alloc;
+    size_t len;
+    char *data;
+};
+
+static void DFUTF16BufferInit(DFUTF16Buffer *buf, size_t alloc)
+{
+    buf->alloc = alloc;
+    buf->len = 0;
+    buf->data = (char *)malloc(buf->alloc*sizeof(char));
+}
+
+static void DFUTF16BufferDestroy(DFUTF16Buffer *buf)
+{
+    free(buf->data);
+}
+
+static void DFUTF16BufferExpand(DFUTF16Buffer *buf)
+{
+    buf->alloc = (buf->alloc == 0) ? 1 : buf->alloc*2;
+    buf->data = (char *)realloc(buf->data,buf->alloc*sizeof(char));
+}
+
+void DFCharEncodingConvert(iconv_t ic, void *data, size_t len, DFUTF16Buffer *output)
+{
+    iconv(ic,NULL,NULL,NULL,NULL); // Reset converter state
+
+    char *inbuf = (char *)data;
+    size_t inbytesleft = len;
+
+    output->len = 0;
+
+    while (inbytesleft > 0) {
+        const char *oldInbuf = inbuf;
+        char *outbuf = &output->data[output->len];
+        size_t outbytesleft = output->alloc - output->len;
+        size_t r = iconv(ic,&inbuf,&inbytesleft,&outbuf,&outbytesleft);
+        if (r == ((size_t)-1)) {
+            if ((errno == EILSEQ) || (errno == EINVAL)) {
+                // Invalid or incomplete multibyte sequence; skip it
+                inbuf++;
+                inbytesleft--;
+                iconv(ic,NULL,NULL,NULL,NULL); // Reset converter state
+
+                // We still want the output that was generated
+                output->len = outbuf - output->data;
+                assert(output->len <= output->alloc);
+
+                continue;
+            }
+        }
+
+        if (oldInbuf == inbuf) {
+            DFUTF16BufferExpand(output);
+        }
+        else {
+            output->len = outbuf - output->data;
+            assert(output->len <= output->alloc);
+        }
+    }
+}
+
+int DFCharEncodingFixChars(uint16_t *chars, NSUInteger len)
+{
+    int changed = 0;
+
+    NSUInteger i = 0;
+    while (i < len) {
+        if (UTF16IsLeadSurrogate(chars[i])) {
+            if ((i+1 < len) && UTF16IsTrailSurrogate(chars[i+1])) {
+                // VALID: Surrogate pair
+                i += 2;
+            }
+            else {
+                // INVALID: Missing trail surrogate
+                chars[i] = '?';
+                changed = 1;
+                i += 1;
+            }
+        }
+        else if (UTF16IsTrailSurrogate(chars[i])) {
+            // INVALID: Unexpected trail surrogate
+            chars[i] = '?';
+            changed = 1;
+            i += 1;
+        }
+        else {
+            // VALID: Single character
+            i += 1;
+        }
+    }
+
+    return changed;
+}
+
+NSString *DFCharEncodingFixNSString(NSString *str)
+{
+    NSUInteger len = str.length;
+    uint16_t *chars = (uint16_t *)malloc(len*sizeof(uint16_t));
+    [str getCharacters: chars range: NSMakeRange(0,len)];
+    if (DFCharEncodingFixChars(chars,len))
+        str = [NSString stringWithCharacters: chars length: len];
+    free(chars);
+    return str;
+}
+
+static void printHex(const void *data, size_t len)
+{
+    const char *chars = (const char *)data;
+    for (size_t i = 0; i < len; i++) {
+        printf("%02X ",(unsigned char)chars[i]);
+    }
+    printf("\n");
+}
+
+static void printChars(const void *data, size_t len)
+{
+    const char *chars = (const char *)data;
+    for (size_t i = 0; i < len; i++) {
+        if ((chars[i] >= 32) && (chars[i] <= 127))
+            printf("%c  ",chars[i]);
+        else
+            printf(".  ");
+    }
+    printf("\n");
+}
+
+void DFCharEncodingTest(void)
+{
+    iconv_t *UTF8toUCS2 = iconv_open("UCS-2-INTERNAL","UTF-8");
+    assert(UTF8toUCS2 != ((iconv_t)-1));
+    printf("u8tou16 = %p\n",UTF8toUCS2);
+
+    iconv_t *UCS2toUTF8 = iconv_open("UTF-8","UCS-2-INTERNAL");
+    assert(UCS2toUTF8 != ((iconv_t)-1));
+    printf("UCS2toUTF8 = %p\n",UCS2toUTF8);
+
+    char *input = "Hello 多语种多多网站";
+    size_t inputLen = strlen(input);
+    printf("%s\n",input);
+
+    printHex(input,inputLen);
+    printChars(input,inputLen);
+    printf("----\n");
+
+    NSString *str = [NSString stringWithCString: input encoding: NSUTF8StringEncoding];
+    uint16_t *chars = (uint16_t *)calloc(1,str.length*sizeof(uint16_t));
+    [str getCharacters: chars range: NSMakeRange(0,str.length)];
+    printHex(chars,str.length*sizeof(uint16_t));
+    printChars(chars,str.length*sizeof(uint16_t));
+    free(chars);
+
+    printf("----\n");
+    DFUTF16Buffer ucs2;
+    DFUTF16BufferInit(&ucs2,0);
+    DFCharEncodingConvert(UTF8toUCS2,input,inputLen,&ucs2);
+    printHex(ucs2.data,ucs2.len);
+    printChars(ucs2.data,ucs2.len);
+
+
+    printf("----\n");
+    DFUTF16Buffer utf8;
+    DFUTF16BufferInit(&utf8,0);
+    DFCharEncodingConvert(UCS2toUTF8,ucs2.data,ucs2.len,&utf8);
+    printHex(utf8.data,utf8.len);
+    printChars(utf8.data,utf8.len);
+
+    char *temp = (char*)malloc(utf8.len+1);
+    memcpy(temp,utf8.data,utf8.len);
+    temp[utf8.len] = '\0';
+    printf("%s\n",temp);
+    free(temp);
+    
+    DFUTF16BufferDestroy(&ucs2);
+    DFUTF16BufferDestroy(&utf8);
+}
+
+NSString *DFFixStringEncoding(NSString *str)
+{
+    return DFCharEncodingFixNSString(str);
+}
+
+NSString *NSStringFromC(const char *cstr)
+{
+    if (cstr == NULL)
+        return NULL;
+    else
+        return [NSString stringWithUTF8String: cstr];
+}
+
+void NSErrorSetFromDFError(NSError **nserror, DFError *dferror)
+{
+    if ((nserror == NULL) || (dferror == NULL))
+        return;
+    [NSError set: nserror format: @"%@", NSStringFromC(DFErrorMessage(&dferror))];
+}
+
+void DFErrorReleaseToNSError(DFError *dferror, NSError **nserror)
+{
+    NSErrorSetFromDFError(nserror,dferror);
+}
+
+void DFErrorSetFromNSError(DFError **dferror, NSError *nserror)
+{
+    if ((nserror == NULL) || (dferror == NULL))
+        return;
+    DFErrorFormat(dferror,"%s",FCErrorDescription(nserror).UTF8String);
+}
+
+BOOL EDStringEquals(NSString *a, NSString *b)
+{
+    if ((a == NULL) && (b == NULL))
+        return YES;
+    else if ((a != NULL) && (b != NULL))
+        return [a isEqualToString: b];
+    else
+        return NO;
+}
+
+NSString *EDEncodeFontFamily(NSString *input)
+{
+    char *cresult = CSSEncodeFontFamily(input.UTF8String);
+    NSString *nsresult = NSStringFromC(cresult);
+    free(cresult);
+    return nsresult;
+}
+
+NSString *EDDecodeFontFamily(NSString *input)
+{
+    char *cresult = CSSDecodeFontFamily(input.UTF8String);
+    NSString *nsresult = NSStringFromC(cresult);
+    free(cresult);
+    return nsresult;
+}

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDWordCount.h
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDWordCount.h b/experiments/objcFramework/EDWordCount.h
new file mode 100644
index 0000000..2d4ce5e
--- /dev/null
+++ b/experiments/objcFramework/EDWordCount.h
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import <Foundation/Foundation.h>
+#import "EDScan.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                      EDWordCountOperation                                      //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface EDWordCountOperation : EDScanOperation
+
+@property (assign, readonly) int words;
+@property (assign, readonly) int chars;
+@property (assign, readonly) int paragraphs;
+
+- (EDScanOperation *)initWithEditor:(EDEditor *)editor;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/EDWordCount.m
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/EDWordCount.m b/experiments/objcFramework/EDWordCount.m
new file mode 100644
index 0000000..e0ee55b
--- /dev/null
+++ b/experiments/objcFramework/EDWordCount.m
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import "EDWordCount.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                                                                                //
+//                                      EDWordCountOperation                                      //
+//                                                                                                //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation EDWordCountOperation
+{
+    NSCharacterSet *_whitespace;
+}
+
+- (EDScanOperation *)initWithEditor:(EDEditor *)editor
+{
+    if (!(self = [super initWithEditor: editor]))
+        return nil;
+    _whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
+    return self;
+}
+
+- (void)processParagraph:(EDScanParagraph *)paragraph
+{
+    NSArray *components = [paragraph.text componentsSeparatedByCharactersInSet: _whitespace];
+    for (NSString *word in components) {
+        if (word.length > 0)
+            _words++;
+    }
+    _chars += paragraph.text.length;
+    _paragraphs++;
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-corinthia/blob/9f851a34/experiments/objcFramework/Editor.h
----------------------------------------------------------------------
diff --git a/experiments/objcFramework/Editor.h b/experiments/objcFramework/Editor.h
new file mode 100644
index 0000000..26ad274
--- /dev/null
+++ b/experiments/objcFramework/Editor.h
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// This file comes from the portion of the UX Write editor that
+// works on both Apple platforms (that is, it can run on either
+// OS X or iOS). It's in the repository for illustrative purposes
+// only, to assist with the creation of the framework for the
+// Corinthia editor UI. The code does not compile independently in
+// its present form.
+
+#import <Foundation/Foundation.h>
+
+#import <Editor/EDEditor.h>
+#import <Editor/EDFileFormat.h>
+#import <Editor/EDFindReplace.h>
+#import <Editor/EDGeometry.h>
+#import <Editor/EDJSInterface.h>
+#import <Editor/EDOutline.h>
+#import <Editor/EDSaveOperation.h>
+#import <Editor/EDScan.h>
+#import <Editor/EDScanResults.h>
+#import <Editor/EDSelectionFormatting.h>
+#import <Editor/EDStyle.h>
+#import <Editor/EDTiming.h>
+#import <Editor/EDUtil.h>
+#import <Editor/EDWordCount.h>


Mime
View raw message